I've been stuck with one lambda expression and the Comparator class using Comparator.comparing(...).thenComparing(...) methods to sum up two way of sorting a Stream.
Both of my methods are working, but when I put them together nothing is working at all.
Here is the link if you want to try and validate the exercise:
http://codecheck.it/codecheck/files?repo=heigvdcs1&problem=poo3e
And here is what you have to do:
For each word in a stream, determine the “vowelness”, i.e. the number of vowels - the number of consonants. Produce the n words with the highest vowelness paired with the vowelness value. Sort first by vowelness, then by the string. Complete this program.
This time, you have a hidden static method long Words.vowels(String w) at your disposal that yields the number of vowels in w, including duplicates.
For now i have managed to do this:
import java.util.*;
import java.util.stream.*;
public class Streams
{
List<Pair<String, Long>> wordsWithManyVowels(Stream<String> words, int n)
{
return words
.map( w -> Pair.of( w , ( Words.vowels(w) - ( w.length() - Words.vowels(w)))))
.sorted(Comparator.comparingLong(f1 -> -f1.second())
//This part is working without the first comparing
//.thenComparing(f2 -> f2.first().length()))
.limit(n)
.collect(Collectors.toList());
}
}
The Pair class:
import java.util.Objects;
public class Pair<T, S>
{
private T first;
private S second;
public Pair(T firstElement, S secondElement)
{
first = firstElement;
second = secondElement;
}
/*
Use Pair.of(x, y) instead of new Pair<...,...>(x, y)
so you get the type inferred
*/
public static <T, S> Pair<T, S> of(T firstElement, S secondElement)
{
return new Pair<T, S>(firstElement, secondElement);
}
public T first() { return first; }
public S second() { return second; }
public String toString() { return "(" + first + "," + second + ")"; }
public boolean equals(Object otherObject)
{
if (this == otherObject)
return true;
if (otherObject == null || !(otherObject instanceof Pair))
return false;
@SuppressWarnings("unchecked") Pair<T, S> other = (Pair<T, S>) otherObject;
return Objects.equals(first, other.first) &&
Objects.equals(second, other.second);
}
}
f2 -> f2.first().length())function is an int extractor, thus shouldn't the method be :thenComparingInt?Long.MIN_VALUE, it doesn’t work due to overflow, the same applies to the minimum values of the other integer types. It’s tempting to say that this will never happen for a particular property, but it will cost you a lot of time once this assumption doesn’t hold anymore and you don’t remember that you made this assumption somewhere in your code. You may just useComparator.comparingLong(Pair<String, Long>::second) .reversed() .thenComparingInt(p -> p.first().length())