Sort Guava Multimap by number of values

If I have Guava cartoons, how would I sort the entries based on the number of values โ€‹โ€‹for this key?

For instance:

Multimap<String, String> multiMap = ArrayListMultimap.create(); multiMap.put("foo", "1"); multiMap.put("bar", "2"); multiMap.put("bar", "3"); multiMap.put("bar", "99"); 

Given this, when repeating several multiplexes, how can I get the "bar" entries to come first (since "bar" has 3 values โ€‹โ€‹versus 1 only for "foo")?

+6
source share
2 answers

Extract the entries in the list, then sort the list:

 List<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>(map.entries()); Collections.sort(entries, new Comparator<Map.Entry<String, String>>() { @Override public int compare(Map.Entry<String, String> e1, Map.Entry<String, String> e2) { return Ints.compare(map.get(e2.getKey()).size(), map.get(e1.getKey()).size()); } }); 

Then iterate over the records.

Edit:

If you want to actually iterate over the internal mapping entries ( Entry<String, Collection<String>> ), follow these steps:

 List<Map.Entry<String, Collection<String>>> entries = new ArrayList<Map.Entry<String, Collection<String>>>(map.asMap().entrySet()); Collections.sort(entries, new Comparator<Map.Entry<String, Collection<String>>>() { @Override public int compare(Map.Entry<String, Collection<String>> e1, Map.Entry<String, Collection<String>> e2) { return Ints.compare(e2.getValue().size(), e1.getValue().size()); } }); // and now iterate for (Map.Entry<String, Collection<String>> entry : entries) { System.out.println("Key = " + entry.getKey()); for (String value : entry.getValue()) { System.out.println(" Value = " + value); } } 
+13
source

I would use Multimap keys Multiset , sort them by descending frequency (which will be easier after the functionality described in question 356 was added in Guava) and build a new Multimap by iterating the sorted keys, getting values โ€‹โ€‹from the original Multimap:

 /** * @return a {@link Multimap} whose entries are sorted by descending frequency */ public Multimap<String, String> sortedByDescendingFrequency(Multimap<String, String> multimap) { // ImmutableMultimap.Builder preserves key/value order ImmutableMultimap.Builder<String, String> result = ImmutableMultimap.builder(); for (Multiset.Entry<String> entry : DESCENDING_COUNT_ORDERING.sortedCopy(multimap.keys().entrySet())) { result.putAll(entry.getElement(), multimap.get(entry.getElement())); } return result.build(); } /** * An {@link Ordering} that orders {@link Multiset.Entry Multiset entries} by ascending count. */ private static final Ordering<Multiset.Entry<?>> ASCENDING_COUNT_ORDERING = new Ordering<Multiset.Entry<?>>() { @Override public int compare(Multiset.Entry<?> left, Multiset.Entry<?> right) { return Ints.compare(left.getCount(), right.getCount()); } }; /** * An {@link Ordering} that orders {@link Multiset.Entry Multiset entries} by descending count. */ private static final Ordering<Multiset.Entry<?>> DESCENDING_COUNT_ORDERING = ASCENDING_COUNT_ORDERING.reverse(); 

EDIT: THIS DOES NOT WORK IF SOME RECORDS HAVE THE SAME FREQUENCY (see my comment)

Another approach using an order based on Multimaps Multiset keys and ImmutableMultimap.Builder.orderKeysBy () :

 /** * @return a {@link Multimap} whose entries are sorted by descending frequency */ public Multimap<String, String> sortedByDescendingFrequency(Multimap<String, String> multimap) { return ImmutableMultimap.<String, String>builder() .orderKeysBy(descendingCountOrdering(multimap.keys())) .putAll(multimap) .build(); } private static Ordering<String> descendingCountOrdering(final Multiset<String> multiset) { return new Ordering<String>() { @Override public int compare(String left, String right) { return Ints.compare(multiset.count(left), multiset.count(right)); } }; } 

The second approach is shorter, but I donโ€™t like the fact that the Ordering state has a state (it depends on the Multimap Multiset key for comparing the keys).

+8
source

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


All Articles