代码之家  ›  专栏  ›  技术社区  ›  coco

Java map<Integer,Integer>流转换为另一个映射(键,list<Integer>)

  •  0
  • coco  · 技术社区  · 2 年前

    可以转换Java吗 Map<Integer, Integer> m0 到一个新的 Map<Integer, List<Integer>> m1 在哪里 m1 要拥有的地图 钥匙 价值 属于 m0 地图和 List<Integer> 属于 钥匙 属于 m0 地图

    换句话说,这个任务是关于反转的 键值对 按值分组。

    我尝试了以下方法:

     public static void main(String[] args) {
            Map<Integer, Integer> m = new HashMap<>();
            m.put(1, 1);
            m.put(2, 1);
            m.put(3, 1);
            m.put(4, 2);
            m.put(5, 2);
            m.put(6, 2);
            m.put(7, 2);
    
            Map<Integer, List<Integer>> personByAge 
                    = m.values()
                    .stream()
                    .collect(Collectors.groupingBy(Function.identity(), Collectors.toList()));
    
            Iterator it = personByAge.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<Integer, List<Integer>> me = (Map.Entry)it.next();
                System.out.println(me.getKey() + " <- key" );
                for (int i : me.getValue())
                {
                    System.out.println("Values: " + i);
                }
            }
        }
    

    但是第二张图中的值是错误的。

    数值应为:

    1 <- key Values: 1 Values: 2 Values: 3
    2 <- key Values: 4 Values: 5 Values: 6 Values: 7
    

    但我得到了:

    1 <- key Values: 1 Values: 1 Values: 1
    2 <- key Values: 2 Values: 2 Values: 2 Values: 2
    
    2 回复  |  直到 2 年前
        1
  •  2
  •   Alexander Ivanchenko    2 年前

    它是关于按值分组的反转键值对

    如果你想像你在评论中说的那样反转映射,你需要在源映射的条目上创建一个流,而不是在值上:

    Map<Integer, List<Integer>> personByAge = m.entrySet()
        .stream()
        .collect(Collectors.groupingBy(
            Map.Entry::getValue,
            Collectors.mapping(Map.Entry::getKey,
                Collectors.toList())));
            
    personByAge.forEach((k, v) -> System.out.println(k + " -> " + v));
    

    输出:

    1 -> [1, 2, 3]
    2 -> [4, 5, 6, 7]
    
        2
  •  0
  •   Shubham Pathak    2 年前
     Map<Integer, List<Integer>> personByAge 
                        = m.entrySet()
                          .stream()
                          .collect(Collectors.groupingBy(
                          Map.Entry::getValue,
                         Collectors.mapping(
                         Map.Entry::getKey,
                         Collectors.toList())));
    
        3
  •  0
  •   Donald Raab    2 年前

    以下将使用 forEach computeIfAbsent

    Map<Integer, List<Integer>> personByAge = new HashMap<>();
    m.forEach((k, v) -> personByAge.computeIfAbsent(v, ArrayList::new).add(k));
    

    最好使用 Set 对于多重类型,因为在迭代 Map ,并且密钥已经是唯一的。

    这实际上是实现了 flip 包含在 Eclipse Collections 在…上 MutableMap . 区别在于 轻弹 返回a MutableSetMultimap . 以下是使用 轻弹 .

    MutableMap<Integer, Integer> m = Maps.mutable.empty();
    m.put(1, 1);
    m.put(2, 1);
    m.put(3, 1);
    m.put(4, 2);
    m.put(5, 2);
    m.put(6, 2);
    m.put(7, 2);
    MutableSetMultimap<Integer, Integer> personByAge = m.flip();
    System.out.println(personByAge);
    

    输出:

    {1=[1, 2, 3], 2=[4, 5, 6, 7]}
    

    因为 轻弹 返回a SetMultimap ,编写测试断言更容易,因为顺序在多值上无关紧要。例如可以为此示例编写以下测试。

    MutableSetMultimap<Integer, Integer> personByAge = m.flip();
    MutableSetMultimap<Integer, Integer> expected =
            Multimaps.mutable.set.<Integer, Integer>empty()
                    .withKeyMultiValues(1, 3, 2, 1)
                    .withKeyMultiValues(2, 7, 5, 6, 4);
    Assertions.assertEquals(expected, personByAge);
    

    如果您的源代码是JDK HashMap ,并且您想要使用流,下面将实现 使用 Collectors2 来自Eclipse集合。

    SetMultimap<Integer, Integer> personByAge = m.entrySet().stream()
            .collect(Collectors2.toSetMultimap(Map.Entry::getValue, Map.Entry::getKey));
    SetMultimap<Integer, Integer> expected =
            Multimaps.mutable.set.<Integer, Integer>empty()
                    .withKeyMultiValues(1, 3, 2, 1)
                    .withKeyMultiValues(2, 7, 5, 6, 4);
    Assertions.assertEquals(expected, personByAge);
    

    注意:我是Eclipse集合的提交者。