如果这是一个我应该知道的简单基本信息,我很抱歉。这是我第一次尝试使用Java 8流和其他功能。
我有两个包含相同类型对象的ArrayLists。我们说list1
和list2
。假设列表中的Person对象具有属性“ employeeId ”。
场景是我需要合并这些列表。但是,list2
可能有一些与list1
中相同的对象。因此,我尝试从list2
中删除与list1
中相同的对象,并获取结果列表,然后我可以在list1
中合并。
我正在尝试使用Java 8 removeIf()和 stream()功能。以下是我的代码:
public List<PersonDto> removeDuplicates(List<PersonDto> list1, List<PersonDto> list2) {
List<PersonDto> filteredList = list2.removeIf(list2Obj -> {
list1.stream()
.anyMatch( list1Obj -> (list1Obj.getEmployeeId() == list2Obj.getEmployeeId()) );
} );
}
上面的代码给出了编译错误,如下所示:
类型Collection中的removeIf(Predicate)方法不适用于参数((list2Obj) - &gt; {})
所以我将“ removeIf()”开头的list2Obj
更改为(<PersonDto> list2Obj)
,如下所示:
public List<PersonDto> removeDuplicates(List<PersonDto> list1, List<PersonDto> list2) {
List<PersonDto> filteredList = list2.removeIf((<PersonDto> list2Obj) -> {
list1.stream()
.anyMatch( list1Obj -> (list1Obj.getEmployeeId() == list2Obj.getEmployeeId()) );
} );
}
这给我一个错误如下:
令牌“&lt;”上的语法错误,删除此令牌以查看(<PersonDto> list2Obj)
中的“&lt; ”和令牌上的语法错误( s),来自' - &gt;的部分错位的构造 {
我对我真正需要做的事情感到茫然。
如果有人可以帮我解决这个问题,我将不胜感激。
答案 0 :(得分:2)
我简化了你的功能,使其更具可读性:
public static List<PersonDto> removeDuplicates(List<PersonDto> left, List<PersonDto> right) {
left.removeIf(p -> {
return right.stream().anyMatch(x -> (p.getEmployeeId() == x.getEmployeeId()));
});
return left;
}
另请注意,您要修改left
参数,而不是创建新的List
。
你也可以使用:left.removeAll(right)
,但是你需要equals
和hashcode
,而你似乎没有它们;或者它们基于employeeId
之外的其他内容。
另一种选择是将这些列表收集到TreeSet
并使用removeAll
:
TreeSet<PersonDto> leftTree = left.stream()
.collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(PersonDto::getEmployeeId))));
TreeSet<PersonDto> rightTree = right.stream()
.collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(PersonDto::getEmployeeId))));
leftTree.removeAll(rightTree);
答案 1 :(得分:2)
据我所知,您正在尝试合并两个列表而不复制属于交叉点的元素。有很多方法可以做到这一点。一种是您尝试过的方式,即从一个列表中删除属于另一个列表的元素,然后合并。反过来,这可以通过多种方式完成。
其中一种方法是将一个列表的员工ID保存在HashSet
中,然后在另一个列表中使用removeIf
,并使用谓词检查每个元素是否具有该员工ID包含在集合中。这比在第一个列表的每个元素的第二个列表上使用anyMatch
更好,因为HashSet.contains
在O(1)
摊销时间内运行。这是解决方案的草图:
// Determine larger and smaller lists
boolean list1Smaller = list1.size() < list2.size();
List<PersonDto> smallerList = list1Smaller ? list1 : list2;
List<PersonDto> largerList = list1Smaller ? list2 : list1;
// Create a Set with the employee ids of the larger list
// Assuming employee ids are long
Set<Long> largerSet = largerList.stream()
.map(PersonDto::getEmployeeId)
.collect(Collectors.toSet());
// Now remove elements from the smaller list
smallerList.removeIf(dto -> largerSet.contains(dto.getEmployeeId()));
这背后的逻辑是HashSet.contains
对于大型和小型集合将花费相同的时间,因为它在O(1)
摊销时间内运行。但是,遍历列表并从中删除元素在较小的列表上会更快。
然后,您已准备好合并两个列表:
largerList.addAll(smallerList);