Stream.collect (groupingBy (identity (), counting ()), and then sort the result by value

I can put together a list of words in a bag (aka multi-set):

Map<String, Long> bag =
        Arrays.asList("one o'clock two o'clock three o'clock rock".split(" "))
        .stream()
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

However, the entries in the bag are not guaranteed in any particular order. For example,

{rock=1, o'clock=3, one=1, three=1, two=1}

I can put them in a list and then sort them using my implementation of a value comparator:

ArrayList<Entry<String, Long>> list = new ArrayList<>(bag.entrySet());
Comparator<Entry<String, Long>> valueComparator = new Comparator<Entry<String, Long>>() {

    @Override
    public int compare(Entry<String, Long> e1, Entry<String, Long> e2) {
        return e2.getValue().compareTo(e1.getValue());
    }
};
Collections.sort(list, valueComparator);

This gives the desired result:

[o'clock=3, rock=1, one=1, three=1, two=1]

Is there a more elegant way to do this? I am sure that this is a problem that many people must solve. Is there something built into the Java Streams API that I can use?

+4
source share
2 answers

, : Map.Entry.comparingByValue. , . , :

Map.Entry.comparingByValue(Comparator.reverseOrder())

.

Collections.sort(list, Map.Entry.comparingByValue(Comparator.reverseOrder()));

.


Map , Stream. , Stream.of(Arrays.asList("...").split(" ")) Pattern.compile(" ").splitAsStream("..."), .

Map<String, Long> bag =
   Pattern.compile(" ")
          .splitAsStream("one o'clock two o'clock three o'clock rock")
          .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
Map<String, Long> sortedBag = 
    bag.entrySet()
       .stream()
       .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
       .collect(Collectors.toMap(
           Map.Entry::getKey,
           Map.Entry::getValue,
           (v1, v2) -> { throw new IllegalStateException(); },
           LinkedHashMap::new
       ));

, LinkedHashMap, .

:

{o'clock=3, rock=1, one=1, three=1, two=1}

StreamEx, :

Map<String, Long> bag =
    StreamEx.split("one o'clock two o'clock three o'clock rock", " ")
            .sorted()
            .runLengths()
            .reverseSorted(Map.Entry.comparingByValue())
            .toCustomMap(LinkedHashMap::new);

, runLengths(). Stream<String, Long>, , . , Stream ["foo", "foo", "bar"] Stream [Entry("foo", 2), Entry("bar", 1)]. , LinkedHashMap.

, 2 .

+6

Bag, , Eclipse Collections:

Bag<String> bag =
    Bags.mutable.with("one o'clock two o'clock three o'clock rock".split(" "));
ListIterable<ObjectIntPair<String>> pairs = bag.topOccurrences(bag.sizeDistinct());
Assert.assertEquals(PrimitiveTuples.pair("o'clock", 3), pairs.getFirst());
Assert.assertEquals(PrimitiveTuples.pair("rock", 1), pairs.getLast());
System.out.println(pairs);

:

[o'clock:3, two:1, one:1, three:1, rock:1]

, , . , SortedBag.

Bag<String> bag =
    SortedBags.mutable.with("one o'clock two o'clock three o'clock rock".split(" "));
ListIterable<ObjectIntPair<String>> pairs = bag.topOccurrences(bag.sizeDistinct());
Assert.assertEquals(PrimitiveTuples.pair("o'clock", 3), pairs.getFirst());
Assert.assertEquals(PrimitiveTuples.pair("two", 1), pairs.getLast());
System.out.println(pairs);

:

[o'clock:3, one:1, rock:1, three:1, two:1]

Pattern.splitAsStream, , , , Collector.toCollection:

Bag<String> bag =
    Pattern.compile(" ").splitAsStream("one o'clock two o'clock three o'clock rock")
        .collect(Collectors.toCollection(TreeBag::new));
ListIterable<ObjectIntPair<String>> pairs = bag.topOccurrences(bag.sizeDistinct());
Assert.assertEquals(PrimitiveTuples.pair("o'clock", 3), pairs.getFirst());
Assert.assertEquals(PrimitiveTuples.pair("two", 1), pairs.getLast());
System.out.println(pairs);

: Eclipse.

+4

Source: https://habr.com/ru/post/1624823/


All Articles