【问题标题】:How to create Map<T, List<K>> out of Map<K, List<T> >?如何从 Map<K, List<T>> > 创建 Map<T, List<K>>?
【发布时间】:2019-07-01 19:23:10
【问题描述】:

我正在尝试实现该功能:

private static <T, K> Map<T, List<K> > invertedMap(Map<K, List<T> > m)

例如,如果我有 Map&lt;String, List&lt;Integer&gt; &gt;

我想创建另一个Map&lt;Integer, List&lt;String&gt; &gt;

我已经写了一些代码:

private static <T, K> Map<T, List<K>> invertedMap(Map<K, T> m) {
    return m.keySet().stream()
            .collect(Collectors.groupingBy(k -> m.get(k)));
}

但正如您所见,这仅在参数中的映射不包含作为值的列表时才有效。

【问题讨论】:

  • 您能否给出一个示例输入和预期结果?

标签: java java-8 hashmap java-stream


【解决方案1】:

我不会为此使用流(如果您想要基于流的解决方案,请查看nullpointer's answer):

private static <T, K> Map<T, List<K>> invertedMap(Map<K, List<T>> map) {
    Map<T, List<K>> result = new LinkedHashMap<>(); // Preserves insertion order 
    map.forEach((k, l) -> 
           l.forEach(t -> result.computeIfAbsent(t, d -> new ArrayList<>()).add(k)));
    return result;
}

上面的代码迭代输入映射map,并且对于每个元素t 的每个Listl,它使用Map.computeIfAbsent 创建结果。

Map.computeIfAbsent 如果给定键有一个条目,则返回该值,或者创建该条目并返回其第二个参数d -&gt; new ArrayList&lt;&gt;() 指定的值(这里d 代表我们不需要的虚拟参数为了创建一个新的空列表)。然后,将键 k 添加到 Map.computeIfAbsent 返回的列表中。

【讨论】:

    【解决方案2】:

    此解决方案类似于answer by Federico Peralta Schaffner 中建议的解决方案,不同之处在于它使用for-loops 而不是forEach。我主要发布这个有一个 MCVE 和一个输入/输出的简短示例,但也作为基于流的解决方案的平衡。现在人们可以争论可读性和可维护性。

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Map.Entry;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Map.Entry;
    
    public class InvertMapWithLists
    {
        public static void main(String[] args)
        {
            Map<String, List<Integer>> map = 
                new LinkedHashMap<String, List<Integer>>();
            map.put("A", Arrays.asList(0,1,2));
            map.put("B", Arrays.asList(2,3,4));
            map.put("C", Arrays.asList(4,5,6));
    
            System.out.println("Original:");
            map.entrySet().forEach(System.out::println);
    
            Map<Integer, List<String>> inverted = invert(map);
    
            System.out.println("Inverted");
            inverted.entrySet().forEach(System.out::println);
        }
    
    
        private static <T, K> Map<T, List<K>> invert(
            Map<K, ? extends Collection<? extends T>> map)
        {
            Map<T, List<K>> result = new LinkedHashMap<T, List<K>>();
    
            for (Entry<K, ? extends Collection<? extends T>> entry : map.entrySet())
            {
                for (T element : entry.getValue())
                {
                    List<K> list = result.computeIfAbsent(
                        element, v -> new ArrayList<K>());
                    list.add(entry.getKey());
                }
            }
            return result;
        }
    }
    

    输出是

    Original:
    A=[0, 1, 2]
    B=[2, 3, 4]
    C=[4, 5, 6]
    Inverted
    0=[A]
    1=[A]
    2=[A, B]
    3=[B]
    4=[B, C]
    5=[C]
    6=[C]
    

    【讨论】:

      【解决方案3】:

      希望这能解决您的问题。

      private static <T, K> Map<T, List<K>> invertedMap(Map<K, List<T>> m) {
          Map<T, List<K>> result = new HashMap<T, List<K>>();
      
          for (K key : m.keySet()) {
              for (T value : m.get(key)) {
                  List<K> kList = null;
                  if ((kList = result.get(value)) == null) {
                      kList = new ArrayList<K>();
                  }
                  kList.add(key);
                  result.put(value, kList);
              }
          }
          return result;
      }
      

      【讨论】:

        【解决方案4】:

        这是一种 stream 方式(虽然我的第一直觉是关注Federico's solution):

        private static <T, K> Map<T, List<K>> invertedMapOfList(Map<K, List<T>> m) {
            return m.entrySet()
                .stream()
                .flatMap(e -> e.getValue()
                    .stream()
                    .map(v -> new AbstractMap.SimpleEntry<>(e.getKey(), v)))
                .collect(Collectors.groupingBy(Map.Entry::getValue,
                    Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-02-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-01-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多