how to pair items from two lists

1.7k views Asked by At

I have two lists of ClassA

List<ClassA> list1;

List<ClassA> list2;

I want to create 4 lists:

List<ClassA> matchedList1;

List<ClassA> matchedList2;

List<ClassA> unmatchedList1;

List<ClassA> unmatchedList2;

where matchedList1 and matchedList2 contain in order items with same classA.name (unique)

unmatchedList1 and unmatchedList2 contain in order items that were not paired.

e.g.

list1 = name1, name2, name3
list2 = name4, name1, name3

matchedList1 = name1, name3 
matchedList2 = name1, name3 

unmatchedList1 = name2
unmatchedList2 = name4

is there any lambda expression to pair items from two lists according to some predicate?

1

There are 1 answers

0
Tagir Valeev On

As you added the lambda tag, I suppose that you are ok with Java-8 solution. Note that your matchedList1 and unmatchedList1 contain all the elements from the list1, so you actually need to partition the list1 according to the predicate of having the same element in list2. This can be done using the partitioningBy collector:

Map<Boolean, List<ClassA>> map1 = list1.stream().collect(
        Collectors.partitioningBy(e1 -> list2.stream().anyMatch(
                e2 -> e1.name.equals(e2.name))));
List<ClassA> matchedList1 = map1.get(true);
List<ClassA> unmatchedList1 = map1.get(false);

You can create matchedList2 and unmatchedList2 exactly in the same way:

Map<Boolean, List<ClassA>> map2 = list2.stream().collect(
        Collectors.partitioningBy(e2 -> list1.stream().anyMatch(
                e1 -> e1.name.equals(e2.name))));
List<ClassA> matchedList2 = map2.get(true);
List<ClassA> unmatchedList2 = map2.get(false);

Note that this solution is not very efficient: its complexity is O(list1.size()*list2.size()). If you worry about the efficiency, it's better to build the sets of the names in both lists before.

Alternatively if your lists are pre-sorted by the name field, you can use the binary search to speedup the procedure:

Comparator<ClassA> comparator = Comparator.comparing(e -> e.name);

Map<Boolean, List<ClassA>> map1 = list1.stream().collect(
    Collectors.partitioningBy(e1 -> Collections.binarySearch(list2, e1, comparator) >= 0));
List<ClassA> matchedList1 = map1.get(true);
List<ClassA> unmatchedList1 = map1.get(false);

Map<Boolean, List<ClassA>> map2 = list2.stream().collect(
    Collectors.partitioningBy(e2 -> Collections.binarySearch(list1, e2, comparator) >= 0));
List<ClassA> matchedList2 = map2.get(true);
List<ClassA> unmatchedList2 = map2.get(false);