【问题标题】:Creating subset of HashMap based on some specifications?根据某些规范创建 HashMap 的子集?
【发布时间】:2013-06-26 21:09:34
【问题描述】:

所以我有以下HashMap:

HashMap<String, List<someDataType>> map;

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

【问题讨论】:

  • 你必须在你的地图上保持额外的约束,才能不必遍历整个地图。例如,如果您的地图按列表的长度升序排序,那么您可以循环直到看到长度超过 x 1。
  • @HunterMcMillen:你知道根据值排序的地图吗?
  • @jlordo 没想到,我想实现 Comparator 并使用 TreeMap 不会那么困难。
  • 你为什么不喜欢这种方法?更简洁...您可以使用一些库(例如 google guava),让您以实用的方式执行此操作
  • @HunterMcMillen: TreeMap 按键排序,无论您如何编写比较器,都不能使用它按值排序。

标签: java hashmap


【解决方案1】:

使用番石榴:

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

【讨论】:

  • +1 击败我 - 但请注意 filterEntries 只会返回底层地图的过滤 view,以防 OP 想要复制它.另外filterValues 会更简洁。
  • 承认使用番石榴,ArrayListMultiMapMultiMaps.filterkeys 不是更合适吗? MultpMaps.filterValues.filterEntries 不起作用,因为您获得了每个单独的值或键值对。
【解决方案2】:

现在(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));

这有助于避免对番石榴的依赖,这可能是不受欢迎的。

【讨论】:

    【解决方案3】:

    如果您的项目可以使用 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);
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        您可能想查看 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);
        

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

        【讨论】:

        • 当我开始写这篇文章的时候,没有答案……我提交的时候,有2个答案来自比我更了解番石榴的人! :-O
        【解决方案6】:

        结合其他 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 的静态内部类,而不是使用匿名内部类。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-10-19
          • 1970-01-01
          相关资源
          最近更新 更多