[英]Sort Guava Multimap by number of values
If I have a Guava Multimap, how would I sort the entries based on the number of values for the given key?如果我有一个 Guava Multimap,我将如何根据给定键的值数量对条目进行排序?
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 iterating over multiMap, how would I get the "bar" entries to come first (since "bar" has 3 values vs. only 1 for "foo")?鉴于此,当迭代 multiMap 时,我如何让“bar”条目先出现(因为“bar”有 3 个值,而“foo”只有 1 个值)?
Extract the entries in a 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 entries.然后遍历条目。
Edit :编辑 :
If what you want is in fact iterate over the entries of the inner map ( Entry<String, Collection<String>>
), then do the following :如果您实际上想要迭代内部映射(
Entry<String, Collection<String>>
)的Entry<String, Collection<String>>
,则执行以下操作:
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);
}
}
I'd use the Multimap's keys Multiset entries, sort them by descending frequency (which will be easier once the functionality described in issue 356 is added to Guava), and build a new Multimap by iterating the sorted keys, getting values from the original Multimap:我会使用 Multimap 的键 Multiset条目,按降序对它们进行排序(一旦将issue 356 中描述的功能添加到 Guava 中会更容易),并通过迭代排序的键来构建新的 Multimap,从原始 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 DOESN'T WORK IF SOME ENTRIES HAVE THE SAME FREQUENCY (see my comment)编辑:如果某些条目具有相同的频率,这将不起作用(请参阅我的评论)
Another approach, using an Ordering based on the Multimaps' keys Multiset, and ImmutableMultimap.Builder.orderKeysBy() :另一种方法,使用基于 Multimaps 键 Multiset 和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));
}
};
}
Second approach is shorter, but I don't like the fact that the Ordering has state (it depends on the Multimap's key Multiset to compare keys).第二种方法较短,但我不喜欢 Ordering 具有状态的事实(它取决于 Multimap 的键 Multiset 来比较键)。
Using Java8 streams:使用 Java8 流:
ListMultimap<String, String> multiMap = ArrayListMultimap.create();
multiMap.put("foo", "f1");
multiMap.put("baz", "z1");
multiMap.put("baz", "z2");
multiMap.put("bar", "b1");
multiMap.put("bar", "b2");
multiMap.put("bar", "b3");
Multimaps.asMap(multiMap).entrySet().stream()
.sorted(Comparator.comparing(e -> -e.getValue().size()))
.forEach(e -> System.out.println(e.getKey() + " -> "
+ Arrays.toString(e.getValue().toArray())));
Output:输出:
bar -> [b1, b2, b3]
baz -> [z1, z2]
foo -> [f1]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.