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

Eli*_*nes 6 java lambda list filter java-stream

我有 2 个包含多个对象的列表。我想过滤在特定属性处包含相同字符串值的对象。因此,假设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);
    }
Run Code Online (Sandbox Code Playgroud)

当然,retainAll()不返回任何内容,因为两个列表只包含不同类型的对象。我如何尝试使用retainAll()对象的特定属性?

非常感谢您提前。

Hol*_*ger 5

您的任务描述不清楚,但显然,您想要获取所有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);
Run Code Online (Sandbox Code Playgroud)

虽然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());
Run Code Online (Sandbox Code Playgroud)

使用commonIDs,您可以根据需要过滤客户列表或许可证列表。


Jos*_*los 2

在这种情况下,您不能使用 keepAll() ,但我会像这样解决问题:

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 + '}';
    }
}
Run Code Online (Sandbox Code Playgroud)