簡體   English   中英

按值的數量對 Guava Multimap 進行排序

[英]Sort Guava Multimap by number of values

如果我有一個 Guava Multimap,我將如何根據給定鍵的值數量對條目進行排序?

例如:

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

鑒於此,當迭代 multiMap 時,我如何讓“bar”條目先出現(因為“bar”有 3 個值,而“foo”只有 1 個值)?

提取列表中的條目,然后對列表進行排序:

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());
    }
});

然后遍歷條目。

編輯 :

如果您實際上想要迭代內部映射( 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);
    }
}

我會使用 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();

編輯:如果某些條目具有相同的頻率,這將不起作用(請參閱我的評論)

另一種方法,使用基於 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));
        }
    };
}

第二種方法較短,但我不喜歡 Ordering 具有狀態的事實(它取決於 Multimap 的鍵 Multiset 來比較鍵)。

使用 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())));

輸出:

bar -> [b1, b2, b3]
baz -> [z1, z2]
foo -> [f1]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM