user739115
user739115

Reputation: 1187

fetch maximum number using stream api

Stream<Integer> stream = Stream.of(2, 1, 3, 4, 2, 3, 2);

If the occurence of the numbers is more, then display that number ,so result is 2

Stream<Integer> stream = Stream.of(2, 1, 3, 4, 2, 3);

If the occurence of the numbers are same for multiple numbers ,then fetch maximum number so result is 2

Optional<Map.Entry<Integer, Long>> sorted1 = stream.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
        .entrySet().stream().filter(k -> k.getValue() > 1).max(Comparator.comparing(Map.Entry::getValue));
        

I have written above logic but not able to fetch both results.

Upvotes: 0

Views: 203

Answers (2)

MC Emperor
MC Emperor

Reputation: 22977

It's also possible to write a custom collector, which is able to collect the highest frequencies in one pass.

class HighestFrequencyContainer {

    // Keep track of the highest frequency
    private long highestFrequency;

    // Keep track of the objects with the highest frequency
    private final Set<T> objectsWithHighestFrequency = new HashSet<>();

    // Keep track of all objects along with their frequencies
    private final Map<T, Long> map = new HashMap<>();

    // Make sure you can add an object
    public void add(T object) { ... }

    // Make sure this container can be merged with another one. We'll utilize this
    // method when we create a custom collector.
    public HighestFrequencyContainer<T> merge(HighestFrequencyContainer<T> container) { ... }

    // Make sure we can get a Set with all objects with the highest frequency
    public Set<T> highestFrequencies() {
        return Set.copyOf(objectsWithHighestFrequency);
    }
}

Then we'll write a collector which utilizes the abovementioned class:

// Creates a Collector returning a Set<T> with all objects with the highest frequency
public static <T> Collector<T, ?, Set<T>> highestFrequency() {
    Collector<T, ?, HighestFrequencyContainer<T>> collector = Collector.of(HighestFrequencyContainer::new, HighestFrequencyContainer::add, HighestFrequencyContainer::merge);
    return Collectors.collectingAndThen(collector, HighestFrequencyContainer::highestFrequencies);
}

At last, we can retrieve the set using

Stream<Integer> stream = Stream.of(2, 1, 3, 4, 2, 3);
Set<Integer> set = stream.collect(MoreCollectors.highestFrequency());

Now the set contains {2, 3}, because those two numbers have the highest frequency (which is 2).

To select the highest number, use a TreeSet:

Integer result = new TreeSet<>(set).pollFirst();

Upvotes: 0

&#201;tienne Miret
&#201;tienne Miret

Reputation: 6650

Use .thenComparing () in order to sort by value among those which have the same count.

Optional<Entry<Integer, Long>> sorted1 = Stream.of (1, 2, 2, 3, 1)
      .collect (Collectors.groupingBy (Function.identity (), Collectors.counting ()))
      .entrySet ()
      .stream ()
      .filter (k -> k.getValue () > 1)
      .max (Comparator.<Map.Entry<Integer, Long>, Long>comparing (Map.Entry::getValue)
        .thenComparing (Map.Entry::getKey)
      );

NB: If you’re only interested in the value, not the count, add .map (Map.Entry::getKey) at the end.

NB: The line filter (k -> k.getValue () > 1) means you’ll get an empty optional for input such as [1] or [1, 2, 3], which may or may not be what you want (dropping it would result in respectively 1 and 3).

Upvotes: 5

Related Questions