Java过滤器列表,它只包含与另一个列表中具有相同属性的对象

时间:2017-06-09 10:02:10

标签: java list lambda filter java-stream

我有两个包含多个对象的列表。我想过滤在特定属性包含相同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()

提前多多谢谢你。

3 个答案:

答案 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,但它应适用于所有类型。