在Java 8中迭代和映射两个列表

10

我有两个列表:

  1. List1: Object1 (name1, id1)
  2. List2: Object2(name2, id2)

假设list1和list2的大小相同

我想遍历list2,如果list2中的name2不为空,则更新list1中的name1。

以下是使用旧版Java的代码:

  for(Object1 obj1:list1) {
    for(Object2 obj2:list2) {
      if(obj1.getId1.equals(obj2.getId2)) {
        obj1.setName1(obj2.getName2);
      }
   }
}

使用java.util.stream,哪种方法是最佳实践?

目前,你的代码具有二次复杂度。你是真的想要检查所有元素的组合,还是只想要检查它们在各自列表中相同索引位置上的元素? - tobias_k
1
“id” 是否意味着您对象的唯一标识符?如果是这种情况,使用以 id 为键的“map”比使用“list”更合适。这还将将时间复杂度降低到 O(n)(在“HashMap”的情况下),而不是 O(n^2)。 - Seelenvirtuose
是的,id是对象的唯一标识符。 - youssef Liouene
3个回答

17

只是为了明确,我认为你的代码旨在完成以下操作:将list1中每个项目的名称更新为与其ID相同的list2中任何项目的名称。似乎没有任何东西检查list1中项目的名称是否为空。

如果这是正确的话,那么:

list2.forEach(obj2 -> list1.stream()
     .filter(obj1 -> obj1.getId().equals(obj2.getId()))
     .forEach(obj1 -> obj1.setName(obj2.getName()));

如果你想检查名字是否为空,则在设置名字之前添加一个新的筛选器:

    .filter(Objects::isNull)

5
如我在评论中提到的,如果id是您对象的唯一标识符,则使用MapList更合适。因此,您最好使用这样的映射(假设id是整数):
Map<Integer, Object1> obj1map;

您可以使用以下方法从第一个列表创建该地图:

obj1map = list1.stream().collect(toMap(Object1::getId, Function.identity()));

现在您可以流式传输第二个列表并相应地更新地图:
list2
    .stream()
    .filter(o -> o.getName() != null) // remove null names
    .filter(o -> obj1map.containsKey(o.getId())) // just to make sure
    .forEach(o -> obj1map.get(o.getId()).setName(o.getName()));

-3

流的概念是它没有上下文。知道你在第一个流中的位置是上下文,你需要找到第二个流中对应的项目。

使用普通的for循环和索引i代替。

for (int i=0; i < list2.size(); i++) {
  Object2 item2 = list2.get(i);
  if (list2.get(i).name != null) {
    list1.get(i).name = item.name;
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接