【问题标题】:How to create a Multimap<K,V> from a Map<K, Collection<V>>?如何从 Map<K, Collection<V>> 创建 Multimap<K,V>?
【发布时间】:2011-03-06 20:25:09
【问题描述】:

我没有找到这样的多地图构造...当我想这样做时,我会遍历地图并填充多地图。还有其他方法吗?

final Map<String, Collection<String>> map = ImmutableMap.<String, Collection<String>>of(
            "1", Arrays.asList("a", "b", "c", "c"));
System.out.println(Multimaps.forMap(map));

final Multimap<String, String> expected = ArrayListMultimap.create();
for (Map.Entry<String, Collection<String>> entry : map.entrySet()) {
    expected.putAll(entry.getKey(), entry.getValue());
}
System.out.println(expected);

第一个结果是{1=[[a, b, c, c]]},但我希望{1=[a, b, c, c]}

【问题讨论】:

    标签: java guava multimap


    【解决方案1】:

    您可以使用com.google.common.collect.Multimaps.flatteningToMultimap 作为您的流收集器。

    给定地图:

    Map<Integer, Collection<String>> map = Map.of(
       1, List.of("a", "b", "c"),
       2, List.of("d", "e", "f"));
    

    您可以执行以下操作:

    Multimap<Integer, String> multimap = map.entrySet().stream()
        .collect(flatteningToMultimap(Map.Entry::getKey, it -> it.getValue().stream(), HashMultimap::create));
    

    【讨论】:

      【解决方案2】:

      还有另一种方法可以使用: Multimaps#newMultimap

      如果您使用扩展 ListSet 的集合,文档建议使用特殊方法 Multimaps#newListMultimapMultimaps#newSetMultimap

      Multimaps.newListMultimap(myMap, ArrayList::new);
      Multimaps.newSetMultimap(myMap, HashSet::new);
      

      【讨论】:

      • 请注意myMap必须为空,否则会抛出IllegalArgumentException。该方法的 Javadoc 声明: > multimap 假定对 map 和工厂返回的列表的完全所有权。这些对象不应手动更新,提供时应为空...
      【解决方案3】:
      LinkedListMultimap<String, String> mm = map.entrySet()
          .stream()
          .collect(
              () -> LinkedListMultimap.create(map.size()),
              (m, e) -> m.putAll(e.getKey(), e.getValue()),
              (m1, m2) -> m1.putAll(m2));
      

      【讨论】:

        【解决方案4】:

        这个问题有点老了,但我想我会给出一个更新的答案。使用 Java 8,你可以做一些类似的事情

        ListMultimap<String, String> multimap = ArrayListMultimap.create();
        Map<String, Collection<String>> map = ImmutableMap.of(
                                   "1", Arrays.asList("a", "b", "c", "c"));
        map.forEach(multimap::putAll);
        System.out.println(multimap);
        

        这应该会根据需要为您提供{1=[a, b, c, c]}

        【讨论】:

        • 我离开 Java 世界已经有一段时间了,但与新语法保持联系总是好的。它消除了一些噪音,我喜欢它。感谢您的更新。也许@kevin-bourrillion 可以用这种语法更新他的答案
        【解决方案5】:

        假设你有

        Map<String, Collection<String>> map = ...;
        Multimap<String, String> multimap = ArrayListMultimap.create();
        

        那我相信这是你能做的最好的了

        for (String key : map.keySet()) {
          multimap.putAll(key, map.get(key));
        }
        

        或者更优化,但更难阅读

        for (Entry<String, Collection<String>> entry : map.entrySet()) {
          multimap.putAll(entry.getKey(), entry.getValue());
        }
        

        【讨论】:

        • 这正是我所做的!请注意,正如 Kevin 在这里指出的那样groups.google.com/group/guava-discuss/browse_thread/thread/… Multimap 是一个 Map,然后如果在原始 Map 中,您有一个空的可迭代值作为值,则不会添加条目“”多地图
        • 创建 miultimap 对我有用:Multimap multimap = ArrayListMultimap.create();它适用于所有 Multimap 已知实现的类。
        【解决方案6】:

        以下代码没有 Google 的 Guava 库。它用于双值作为键和排序顺序

        Map<Double,List<Object>> multiMap = new TreeMap<Double,List<Object>>();
        
        for( int i= 0;i<15;i++)
        {
            List<Object> myClassList = multiMap.get((double)i);
            if(myClassList == null)
            {
                myClassList = new ArrayList<Object>();
                multiMap.put((double) i,myClassList);
            }
            myClassList.add("Value "+ i);
        }
        
        List<Object> myClassList = multiMap.get((double)0);
        if(myClassList == null)
        {
            myClassList = new ArrayList<Object>();
            multiMap.put( (double) 0,myClassList);
        }
        myClassList.add("Value Duplicate");
        for (Map.Entry entry : multiMap.entrySet()) 
        {
          System.out.println("Key = " + entry.getKey() + ", Value = " +entry.getValue());
        }
        

        【讨论】:

          【解决方案7】:

          这是我为StuffGuavaIsMissing 班级编写的一个有用的通用版本。

          /**
           * Creates a Guava multimap using the input map.
           */
          public static <K, V> Multimap<K, V> createMultiMap(Map<K, ? extends Iterable<V>> input) {
            Multimap<K, V> multimap = ArrayListMultimap.create();
            for (Map.Entry<K, ? extends Iterable<V>> entry : input.entrySet()) {
              multimap.putAll(entry.getKey(), entry.getValue());
            }
            return multimap;
          }
          

          还有一个不可变的版本:

          /**
           * Creates an Immutable Guava multimap using the input map.
           */
          public static <K, V> ImmutableMultimap<K, V> createImmutableMultiMap(Map<K, ? extends Iterable<V>> input) {
            ImmutableMultimap.Builder<K, V> builder = ImmutableMultimap.builder();
            for (Map.Entry<K, ? extends Iterable<V>> entry : input.entrySet()) {
              builder.putAll(entry.getKey(), entry.getValue());
            }
            return builder.build();
          }
          

          【讨论】:

          • 这些有点不灵活,因为它们迫使您使用特定的 Multimap 实现。
          • @Michael 嗯,我无法想象有很多东西比互联网上发布的免费开源代码 sn-p更少不灵活:)
          • @DanielAlexiuc 呵呵。不过,这不是我的意思。如果您在整个代码中使用了第一个函数,然后随后需要更改在其中一半情况下返回的 Multimap 的类型,那么您将面临一些维护噩梦。我认为通过参数传递Multimap 是一个更好的设计。
          【解决方案8】:

          更新:对于您的要求,我认为您需要退回到Multimap.putAll

          【讨论】:

          • 谢谢,但是当我问这个问题时,我已经尝试过这个类的一些功能......以及其他方式......但唯一对我有用的是迭代地图...
          • @Sylvian:既然您将此答案标记为已接受,这是否意味着您的问题现在已经真正解决了?看起来不像,因为你没有以任何方式提到这一点。只是想知道,否则其他人发布更详细/合适的答案会浪费时间。
          • Multimaps.newMultimap(map, new Supplier&lt;List&lt;String&gt;&gt;(){ public List&lt;String&gt; get() { return new ArrayList&lt;String&gt;();}});怎么样
          • 它不起作用,因为 Multimaps.newMultimap() 需要一个空地图作为第一个参数
          • @Mark Peters 是的,关于那套方法的 Javadoc 可能需要一些帮助。该要求应该在参数文档中,而不仅仅是在异常文档中。
          猜你喜欢
          • 2011-07-31
          • 1970-01-01
          • 1970-01-01
          • 2011-04-21
          • 1970-01-01
          • 2019-10-10
          • 2018-11-23
          • 2021-06-17
          • 1970-01-01
          相关资源
          最近更新 更多