如何以最有效的方式迭代列表并为其设置数据?
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;
}
}
}
您的代码中有几点需要注意:
- .filter 应该 return 一个布尔值,以便它过滤记录。但在你的情况下,这并没有发生。您应该对内部过滤器输出进行计数,看看它是否大于 0。或者,简化它并使用 anyMatch
- .map 期望得到相同 entity/class 的响应。但是当你使用 setter 时,你 return 无效,因此你的 setter 并没有真正生效。使用不同的自定义 setter return 更新的对象,或者使用代码块 return 更新的对象。
- .map 不是终端操作。因此,整个表达式甚至都没有被执行。你会想要一个像收集这样的终端操作,或者甚至只是一个让轮子运动的计数
- 看起来您正在为 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));
我正在处理一个问题,我需要迭代一个 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;
}
}
}
您的代码中有几点需要注意:
- .filter 应该 return 一个布尔值,以便它过滤记录。但在你的情况下,这并没有发生。您应该对内部过滤器输出进行计数,看看它是否大于 0。或者,简化它并使用 anyMatch
- .map 期望得到相同 entity/class 的响应。但是当你使用 setter 时,你 return 无效,因此你的 setter 并没有真正生效。使用不同的自定义 setter return 更新的对象,或者使用代码块 return 更新的对象。
- .map 不是终端操作。因此,整个表达式甚至都没有被执行。你会想要一个像收集这样的终端操作,或者甚至只是一个让轮子运动的计数
- 看起来您正在为 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));