【问题标题】:Update one list based on another list using stream使用流基于另一个列表更新一个列表
【发布时间】:2018-08-27 11:58:31
【问题描述】:

我想从传入列表更新现有列表中的项目。

class Person{
  String id;
  String name;
  String age;
.
.
.
  @Override
  public boolean equals(Object object) {
    return ... ((Person) object).id.equals(this.id);
  }
}

当前列表较短:

ArrayList<Person> currentList = Arrays.asList(
   new Person("0", "A", 25),
   new Person("1", "B", 35)
);

接收到的列表更大,例如

ArrayList<Person> updatedList = Arrays.asList(
       new Person("0", "X", 99),
       new Person("1", "Y", 100),
       new Person("2", "C", 2),
       new Person("3", "D", 3),
       new Person("4", "E", 5)
    );

包括当前列表中的项目(由其id标识)。

我想用新列表中的相同项目替换当前列表中的所有项目。

所以转换后,当前列表将是

{ Person(0, "X", 99), Person(1, "Y", 100) }

是否可以只使用 Stream。

【问题讨论】:

  • 我怀疑你能找到比两个嵌套循环更优雅的解决方案。对于较大的列表,将一个列表转换为 Map 并只执行一个循环是有道理的,但对于如此短的列表,它不会得到回报。
  • person 类是否只有三个字段?您想只更新另一个列表中的两个字段(姓名和年龄)吗?
  • @pvpkiran 嗨,它可能有更多字段。由于可能会更新任何字段,因此我想将新列表中的对象直接替换为旧列表。
  • 缺少很多细节。如果更新列表中不存在某些 id 怎么办?我们谈论的清单有多大?
  • 您所说的“操作员”是什么意思,您是否有理由要使用流?使用Collection 方法removeAllretainAlladdAll。可能就足够了,并且可能有助于提高可读性。我认为,对于小型列表,性能不会有所不同。

标签: java arraylist lambda java-8 java-stream


【解决方案1】:

如果currentList 始终是updatedList 的子集 - 意味着所有currentList 都将出现在updatedList 中,您可以执行以下操作:

Set<String> setOfId = currentList.stream()
                                 .map(person -> person.getId()) // exctract the IDs only
                                 .collect(Collectors.toSet());  // to Set, since they are unique

List<Person> newList = updatedList.stream()                     // filter out those who don't match
                                  .filter(person -> setOfId.contains(person.getId()))  
                                  .collect(Collectors.toList());

如果updatedListcurrentList 明显不同——两者都可以有唯一的人,你必须进行双重迭代并使用Stream::map 替换Person。如果没有找到,替换为self:

List<Person> newList = currentList.stream()
    .map(person -> updatedList.stream()                                       // map Person to
                              .filter(i -> i.getId().equals(person.getId()))  // .. the found Id
                              .findFirst().orElse(person))                    // .. or else to self
    .collect(Collectors.toList());                                            // result to List

【讨论】:

    【解决方案2】:

    假设您希望 currentList 项目被 updatedList 中的对象替换,以下应该可以工作:

    currentList.stream().map((p) -> {
                return updatedList.stream().filter(u -> p.equals(u)).findFirst().orElse(p);
            }).collect(Collectors.toList());
    

    【讨论】:

      【解决方案3】:

      这将实现您的要求。

       Map<String, Person> collect = updatedList
                                     .stream()
                                     .collect(Collectors.toMap(Person::getId, Function.identity()));
      
       currentList = currentList
                     .stream()
                     .map(Person::getId)
                     .map(collect::get)
                     .collect(Collectors.toList());
      

      正如@Holger 提到的,为一个小列表做这个并不是那么优雅

      【讨论】:

        【解决方案4】:

        是的,可以使用流,

        1. 从 currentList 中查找所需的 id 列表
        2. 过滤在第一个列表中具有 id 的记录

          List<String> ids = currentList.stream().map(Person::getId).collect(Collectors.toList());
          currentList = updatedList.stream().filter(o -> ids.contains(o.getId()))
                                            .collect(Collectors.toList());
          

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-12
          • 2019-08-10
          • 1970-01-01
          • 2015-05-02
          • 2016-07-14
          相关资源
          最近更新 更多