5

所以我有以下HashMap:

HashMap<String, List<someDataType>> map;

我想创建一个新的 HashMap,它只由 k/v 对组成,其中map的值(列表)的长度小于某个“x”。我知道如何做到这一点的唯一方法是遍历 HashMap 并将 k/v 对放入一个新的 HashMap 中。有没有更简洁的方法来实现我正在寻找的东西?谢谢。

4

6 回答 6

11

使用番石榴:

Map<String, List<String>> newMap = 
    Maps.filterEntries(originalMap, new MyEntryPredicate(10));

在哪里:

private static class MyEntryPredicate implements Predicate<Map.Entry<String, List<String>>> {

    // max list length, exclusive
    private int maxLength;

    private MyEntryPredicate(int maxLength) {
        this.maxLength = maxLength;
    }

    @Override
    public boolean apply(Map.Entry<String, List<String>> input) {
        return input != null && input.getValue().size() < maxLength;
    }
}
于 2013-06-26T21:19:46.257 回答
5

如果您的项目可以使用Guava库,您可以使用Maps.filterValues(有点呼应 Keith 的回答):

final int x = 42;

Map<String, List<String>> filteredMap =
        Maps.filterValues(map, new Predicate<Collection<?>>() {
            @Override
            public boolean apply(final Collection<?> collection) {
                return collection.size() < x;
            }
        });

Map<String, List<String>> filteredMapCopy = ImmutableMap.copyOf(filteredMap);

请注意需要复制,因为filterValues返回原始地图的过滤视图

更新:使用 Java 8,您可以将谓词简化为 lambda 表达式:

Map<String, List<String>> filteredMap = Maps.filterValues(map, list -> list.size() < x);
于 2013-06-26T21:24:12.513 回答
1

如今(Java 8+)这可以通过流来完成:

Predicate<Map.Entry<String, List<String>>> test = entry -> entry.getValue().size() <= x; // note this is java.util.function.Predicate
Map<String, List<String>> filteredMap = map.entrySet().stream().filter(test)
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

这有助于避免可能不希望的对番石榴的依赖。

于 2020-01-14T14:05:18.777 回答
0

或者,您可以制作原始地图的副本并迭代删除长度小于 x 的值。

于 2013-06-26T21:18:19.843 回答
0

您可能想查看 Google 的Guava库。那里有大量相关CollectionsMap实用程序,可以让你非常简洁地完成复杂的事情。你可以做的一个例子是:

Iterable<Long> list = 
    Iterables.limit(
        Iterables.filter(
            Ordering.natural()
                    .reverse()
                    .onResultOf(new Function<Long, Integer>() {
                        public Integer apply(Long id) {
                            return // result of this is for sorting purposes
                        }
                    })
                    .sortedCopy(
                        Multisets.intersection(set1, set2)),
                new Predicate<Long>() {
                    public boolean apply(Long id) {
                        return // whether to filter this id
                    }
                }), limit);

我相信你可以在那里找到可以做你正在寻找的东西:-)

于 2013-06-26T21:25:07.373 回答
0

与其他 Guava 示例一起,您可以使用 Guava 的MultiMaps:

final MultiMap<K, V> mmap = ArrayListMultiMap.create();
// do stuff.
final int limit = 10;
final MultiMap<K, V> mmapView =
    MultiMaps.filterKeys(mmap, new Predicate<K>(){
        public boolean apply(K k) {
            return mmap.get(k).size() <= limit;
        }
});

MultiMaps.newListMultiMap方法接受您不想提供的参数。您不能在此处使用MultiMaps.filterValues.filterEntries,因为它们使用单​​个值,而不是值列表。另一方面,mmap.get(k)永远不会返回null。当然,您可以使用您传递的静态内部类,mmaplimit不是使用匿名内部类。

于 2013-06-26T21:43:03.673 回答