【问题标题】:Java 8 join two lists of mapsJava 8 加入两个地图列表
【发布时间】:2017-06-01 15:08:46
【问题描述】:

在 Java8 中有什么方法可以使用 Streams API 来加入两个地图列表吗? 假设我有:

列表 #1

[  
   {  
      id=1, attr1='a', attr2='b'
   },
   {  
      id=2, attr1='c', attr2='d'
   },
   {  
      id=3, attr1='e', attr2='f'
   }
]

列表 #2

[  
       {  
          id=1, attr3='x', attr4='y'
       },
       {  
          id=2, attr3='x', attr4='z'
       },
       {  
          id=3, attr3='z', attr4='y'
       }
    ]

现在我想通过键 ID 加入这两个列表(只需列出一个 SQL 连接), 输出将是:

[  
       {  
          id=1, attr1='a', attr2='b', attr3='x', attr4='y'
       },
       {  
          id=2, attr1='c', attr2='d', attr3='x', attr4='z'
       },
       {  
          id=3, attr1='e', attr2='f', attr3='z', attr4='y'
       }
    ]

非常感谢!

【问题讨论】:

  • 你尝试了什么?这不是代码编写服务。
  • 这看起来很像 Javascript,尽管它可能只是伪代码。 :) 然而,在实际的 Java 代码中,地图会是什么样子?我假设id 是关键,但第一个列表中的attrib1attrib2 是什么?值对象的属性?嵌套集合中的元素?
  • 您可以在 java 8 中进行集合连接。请参阅this。尝试解决您的问题。
  • @Thomas 抱歉,我没说这个结构代表 Maps 的列表,id、attr1、attr2、attr3 和 attr4 是键。
  • 这是否意味着您的地图的键类型是String?值类型,是IntegerCharacterObject 还是什么?此外,保存具有相同id 值(在您的示例中为 1、2 和 3)的地图是否需要列表?如果其中一个列表中有一张“额外”的地图怎么办?它们的顺序相同吗?

标签: java dictionary join merge java-stream


【解决方案1】:
final List<HashMap<String, String>> joinedById = list1.stream()
            .flatMap(m1 -> list2.stream()
                    .filter(y -> m1.get("id").equals(y.get("id")))
                    .map(m2 -> new HashMap<String, String>() {{
                        putAll(m1);
                        putAll(m2);
                    }}))
            .collect(Collectors.toList());

【讨论】:

    【解决方案2】:

    有很多方法,有和没有流。最好的方法取决于您没有给我们的更准确的输入要求。以下内容适用于您问题中的示例列表:

        if (list1.size() != list2.size()) {
            throw new IllegalStateException("Lists don’t match, not same size");
        }
    
        List<Map<String, Character>> comnbinedList = IntStream.range(0, list1.size())
                .mapToObj(i -> {
                        Map<String, Character> m1 = list1.get(i);
                        Character id1 = m1.get("id");
                        Map<String, Character> m2 = list2.get(i);
                        Character id2 = m1.get("id");
                        if (! id1.equals(id2)) {
                            throw new IllegalStateException("Lists don’t match, id " + id1 + " != " + id2);
                        }
                        HashMap<String, Character> mergedMap = new HashMap<>(m1);
                        mergedMap.putAll(m2);
                        return mergedMap; 
                    })
                .collect(Collectors.toList());
    

    结果是:

    [{id=1, attr2=b, attr1=a, attr4=y, attr3=x}, {id=2, attr2=d, attr1=c, attr4=z, attr3=x}, {id=3, attr2=f, attr1=e, attr4=y, attr3=z}]
    

    当然,您需要将"id" 声明为常量。

    【讨论】:

      【解决方案3】:

      你在map中使用id键的数据结构;有点让这有点不寻常,但这里有一个流收集器的例子。由于您的地图值既是int 又是String 我使用了Map&lt;String, Object&gt;

      import java.util.*;
      public class JoinTwoListofMaps {
          public static void main(String... args){
              List<Map<String, Object>> list1 = new ArrayList<>();
              List<Map<String, Object>> list2 = new ArrayList<>();
              Map<String, Object> map1_1 = new HashMap<>();
                  map1_1.put("id",1);
                  map1_1.put("attr1","a");
                  map1_1.put("attr2","b");
              list1.add(map1_1);
              Map<String, Object> map2_1 = new HashMap<>();
                  map2_1.put("id",1);
                  map2_1.put("attr3","x");
                  map2_1.put("attr4","y");
              list2.add(map2_1);
              System.out.println(joinTwoListOfMaps(list1, list2));
          }
          @SafeVarargs
          public static List<Map<String, Object>> joinTwoListOfMaps(List<Map<String, Object>>... listsOfMaps){
              List<Map<String, Object>> finalList = Arrays.stream(listsOfMaps).collect(ArrayList::new, List::addAll, List::addAll);
              return finalList.stream().collect(ArrayList::new, (list, mapToMerge) ->{
                  Optional<Map<String, Object>> mapWithSameID = list.stream()
                          .filter(map -> map.get("id").equals(mapToMerge.get("id"))).findFirst();
                  if (mapWithSameID.isPresent()) mapWithSameID.get().putAll(mapToMerge);
                  else list.add(mapToMerge);
              }, ArrayList::addAll);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-22
        • 2011-08-05
        • 1970-01-01
        • 1970-01-01
        • 2019-01-15
        • 2012-03-12
        • 2017-03-02
        • 1970-01-01
        相关资源
        最近更新 更多