我有两个包含多个对象的列表。我想过滤在特定属性包含相同String值的对象。
因此,我们假设listA
包含属性为id
的对象。 listB
也是如此,尽管它包含不同的对象。两个列表中的某些对象具有相同的ID。我想过滤这些对象并将它们放在一个新列表中。这是我到目前为止所得到的:
List<Customer> Clist = Customer.getAllCustomers();
List<License> Llist = License.getAllLicenses();
Predicate<Customer> customerNotNullPredicate = u -> (u.id != null);
Predicate<License> licenseNotNullPredicate = u -> (u.id != null);
List<Customer> Clistfiltered1 = Clist.parallelStream().filter(customerNotNullPredicate).collect(Collectors.toList());
List<License> Llistfiltered1 = Llist.parallelStream().filter(licenseNotNullPredicate).collect(Collectors.toList());
Clistfiltered1.retainAll(Llistfiltered1);
try {
Clistfiltered1.get(0);
} catch (Exception e){
System.out.println(e);
}
如果是课程,retainAll()
不返回任何内容,因为两个列表只包含不同类型的对象。如何尝试在对象的特定属性上使用retainAll()
?
提前多多谢谢你。
答案 0 :(得分:3)
您的任务说明不明确,但显然,您希望获得所有Customer
实例,其中License
实例存在相同的id
。
虽然可以将其描述为一个流操作,但是在一个列表中为另一个列表的每个元素搜索匹配将意味着O(nxm)
时间复杂度的操作,换句话说,它将执行非常如果您有大型名单,那就太糟糕了。
因此,最好在具有O(n+m)
时间复杂度的两个操作中执行此操作:
List<Customer> cList = Customer.getAllCustomers();
List<License> lList = License.getAllLicenses();
Set<?> licenseIDs = lList.stream()
.map(l -> l.id).filter(Objects::nonNull)
.collect(Collectors.toSet());
List<Customer> cListFiltered = cList.stream()
.filter(c -> licenseIDs.contains(c.id))
.collect(Collectors.toList());
if(cListFiltered.isEmpty()) System.out.println("no matches");
else cListFiltered.forEach(System.out::println);
虽然Set
返回的确切collect(Collectors.toSet())
类型未指定,但您可以预期它具有优于线性查找,这允许在后续流操作中使用其contains
方法。请注意,只有第一个操作具有null
值的过滤器;由于这可以保证licenseIDs
集不包含null
,因此隐式拒绝具有null
ID的客户。
很容易获得公共ID
Set<?> commonIDs = cList.stream()
.map(l -> l.id).filter(licenseIDs::contains)
.collect(Collectors.toSet());
使用commonIDs
,您可以根据需要同时过滤客户列表或许可证列表。
答案 1 :(得分:2)
在这种情况下你不能使用retainAll(),但我会解决这个问题:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class DifferentCollections {
public static void main(String[] args) {
List<Customer> customers = new ArrayList<>(Arrays.asList(new Customer(1), new Customer(2), new Customer(10)));
List<License> licenses = new ArrayList<>(Arrays.asList(new License(1), new License(2), new License(30)));
List<Customer> filteredCustomers = customers.stream().
filter(c -> customerIdFoundInLicensesList(c, licenses)).
collect(Collectors.toList());
System.out.println(filteredCustomers);
}
private static boolean customerIdFoundInLicensesList(Customer customer, List<License> licenses) {
return licenses.stream().
filter(l -> l.getId().equals(customer.getId())).
findAny().
isPresent();
}
}
class Customer {
Integer id;
public Customer(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
@Override
public String toString() {
return "Customer{" + "id=" + id + '}';
}
}
class License {
Integer id;
public License(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
@Override
public String toString() {
return "License{" + "id=" + id + '}';
}
}
答案 2 :(得分:1)
您无法在两种不同类型(客户和许可证)之间执行retainAll操作。我建议你只找到两个集合中的ID,然后根据需要使用它们
output.html
显然,不确定你的案例中的id是否为Long,但它应适用于所有类型。