Reputation: 2219
How to find most frequent element, but when there are few most frequent element return null.
I would like to find code equivalent of:
public static void main(String[] args) {
System.out.println("Should return A -> " + mostFrequent(Arrays.asList("A", "A", "B")));
System.out.println("Should null as element in list have same frequency -> "
+ mostFrequent(Arrays.asList("A", "B")));
}
private static String mostFrequent(List<String> elements) {
Map<String, Long> ordered = new TreeMap<>();
for (String e : elements) {
if (!ordered.containsKey(e)) {
ordered.put(e, 0L);
}
Long tmp = ordered.get(e);
ordered.put(e, ++tmp);
}
String mostFrequent = null;
long i = 0;
Iterator<Map.Entry<String, Long>> it = ordered.entrySet().iterator();
while (it.hasNext() && i < 2) {
Map.Entry<String, Long> pair = it.next();
if (i == 0) {
mostFrequent = pair.getKey();
} else {
if (ordered.get(mostFrequent) == ordered.get(pair.getKey())) {
return null;
}
}
i++;
}
return mostFrequent;
}
However stream version does not handle most frequent elements with the same frequency.
private static String mostFrequentStream(List<String> elements) {
return elements.stream()
.reduce(BinaryOperator.maxBy(
Comparator.comparingInt(o -> Collections.frequency(elements, o))))
.orElse(null);
}
How to modify stream above to achieve it?
Upvotes: 0
Views: 3397
Reputation: 5183
I managed to build a concatenated Stream
but it got long:
private static String mostFrequentStream3(List<String> elements) {
return elements.stream() // part 1
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet().stream() // part 2
.collect(Collectors.groupingBy(Entry::getValue))
.entrySet().stream() // part 3
.max(Entry.comparingByKey())
.map(Entry::getValue)
.filter(v -> v.size() == 1)
.map(v -> v.get(0).getKey())
.orElse(null);
}
To "find most frequent element, but when there are few most frequent element return null"
Part 1 counts the frequency of every element.
Part 2 groups entries by frequency.
Part 3 looks up the entry with the highest frequency. If this entry does only have one element ("there are few most frequent"), then it's the one and only maximum. Otherwise null
is returned.
Upvotes: 2
Reputation: 56453
using groupingBy:
String mostFrequentStream(List<String> elements) {
Map<String, Long> temp = elements.stream()
.collect(Collectors.groupingBy(a -> a, Collectors.counting()));
return new HashSet<>(temp.values()).size() < temp.size() ?
null : temp.entrySet()
.stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey).get();
}
Upvotes: 4
Reputation: 2727
I would never use stream for this to avoid hurting readability and performance at the same time. For the sake of fun -
private static String mostFrequentStream(List<String> elements) {
Map<String, Long> frequencyMap = elements.stream().collect(groupingBy(Function.identity(), counting()));
return frequencyMap.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(2).reduce((i, e) -> i.getValue().equals(e.getValue()) ? new AbstractMap.SimpleEntry<>(null, 0L) : i).get().getKey();
}
Upvotes: -1