如何以最有效的方式迭代列表并为其设置数据?

How to iterate a List and set data to it in most efficient way?

我正在处理一个问题,我需要迭代一个 N 大小的数组列表并与另一个列表进行比较,对于所有匹配的元素,我需要在其上设置一些数据。下面给出了示例和到目前为止我尝试过的内容。

List<Emp> emp= new ArrayList<>(); 
List<Student> stud = new ArrayList<>();
 
class Emp -> int id, String status, String name; 
class Student -> int id, String studStatus, String name;

如果学生和员工的 ID 匹配,则使用一些默认值更新 emp 状态。

到目前为止,我尝试了这段代码,但它并没有帮助我获得所需的结果。纠正我我在这里做错了什么?

  stud.stream().filter(i -> emp.stream().filter(j ->
 j.getId().equals(i.getId()))
                                .map(i -> i.setStatus(Status.PASS)));

一个map是一个中间操作。除非您将终端操作附加到流管道,否则不会调用流管道。

为避免二次时间复杂度,通过构建 Map<Integer, Emp>.

进行预处理
Map<Integer, Emp> empData = emp.stream()
     .collect(Collectors.toMap(Emp::getId, Function.identity()));

如果有多个 Emp 对象具有相同的 Id,这将抛出异常。

接下来,遍历学生并从上面的映射中获取适当的 Emp 实例并更改状态

stud.stream()
    .filter(student -> empData.containsKey(student.getId()))
    .forEach(student -> empData.get(student.getId()).setStatus(Status.PASS));

流并不比 for 循环更有效,所以使用:

    int studSize = stud.size();
    int empSize = emp.size();
    for(int i=0; i<studSize; i++) {
        for(int j=0; j<empSize; j++) {
            if (stud.get(i).getId() == emp.get(j).getId) {
                stud.setStatus(Status.PASS);
                break;
            }
        }
    }

您的代码中有几点需要注意:

  1. .filter 应该 return 一个布尔值,以便它过滤记录。但在你的情况下,这并没有发生。您应该对内部过滤器输出进行计数,看看它是否大于 0。或者,简化它并使用 anyMatch
  2. .map 期望得到相同 entity/class 的响应。但是当你使用 setter 时,你 return 无效,因此你的 setter 并没有真正生效。使用不同的自定义 setter return 更新的对象,或者使用代码块 return 更新的对象。
  3. .map 不是终端操作。因此,整个表达式甚至都没有被执行。你会想要一个像收集这样的终端操作,或者甚至只是一个让轮子运动的计数
  4. 看起来您正在为 Status 使用枚举,但 类 似乎不是这样定义的...

如果你想保留你的代码并进行更正.. 下面是你可以做的

    stud.stream()
        .filter(i -> emp.stream().filter(j -> j.getId() == i.getId()).count() > 0L) // ensure the outer filter is getting a boolean output
        .map(i -> {
            i.setStudStatus(Status.PASS);
            return i; // unless you return, the setter does not take effect
            })
        .count(); // terminal operation

如果您接受稍微不同的方法并简化初始过滤器,并使用更好的方法终止而不是映射和计数,那么请按照下面的方法(推荐)

    stud.stream()
        .filter(s -> {return emp.stream().anyMatch(e -> (e.id == s.id)); }) 
        .forEach(s -> s.setStatus(Status.PASS));

最简单的方法是首先像这样创建一组所有学生 ID:

Set<Integer> studentIds = stud.stream()
     .map(Student::getId)
     .collect(Collectors.toSet());

通过使用 Set 而不是 List 我们也避免了重复的 ID。

现在我们可以遍历员工并查看员工 ID 是否包含在学生 ID 集中。如果是,我们更新员工的状态。

emp.stream()
    .filter(studentIds::contains)
    .forEach(employee -> employee.setStatus(Status.PASS));