I got 2 lists containing several objects. I want to filter the objects that contain the same String value at a specific attribute.
So let's say listA
contains objects with attribute id
. Same for listB
, although it contains different objects. Some objects from both lists have the same id though. I want to filter these objects and put them in the a new list. This is what i got so far:
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);
}
If course, retainAll()
doesn't return anything, as both lists just contain objects of the different type. How can i try to use retainAll()
on a specific attribute of the objects?
Thank you a lot in advance.
Your task description is not clear, but apparently, you want to get all Customer
instance, for which a License
instance having the same id
exist.
While it is possible to describe this as one stream operation, searching for a match in one list for every element of the other list would imply an operation of O(nxm)
time complexity, in other words, it would perform very bad if you have large lists.
Therefore, it’s better to do it in two operations having O(n+m)
time complexity:
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);
While the exact Set
type returned by collect(Collectors.toSet())
is unspecified, you can expect it to have a better than linear lookup, which allows to use its contains
method in the subsequent stream operation. Note that only the first operation has a filter for null
values; since that guarantees that the licenseIDs
set does not contain null
, customers with a null
id are rejected implicitly.
It’s easy to get the common IDs instead
Set<?> commonIDs = cList.stream()
.map(l -> l.id).filter(licenseIDs::contains)
.collect(Collectors.toSet());
Using commonIDs
, you may filter both, the lists of customers or the list of licenses, if you wish.
in this case you can't use retainAll() , but I would solve the problem like this:
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 + '}';
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With