Im trying to use Java 8 streams to combine lists. How can I get a \"symmetric difference list\" (all object that only exist in one list) from two existing lists. I know how
disjoint = A and B are disjoint if their intersect is empty.
A disjoint is not a set, it is an indicator showing if two sets are disjoint or not. From your description I think you where searching the symmetric difference.
But anyhow, if you only want to collect to new Lists then all you need is a collector.
I made a method that creates an Collector. This Collector only "collects" values, where the predicate is evaluated to true. So if you are searching for the symmetric difference, than you only need a predicate.
public void testDisjointLists() {
List bigCarList = get5DefaultCars();
List smallCarList = get3DefaultCars();
Collector, ArrayList> inter
= produceCollector(car -> {
return bigCarList.contains(car) && smallCarList.contains(car);
});
Collector, ArrayList> symDiff
= produceCollector(car -> {
return bigCarList.contains(car) ^ smallCarList.contains(car);
});
//Get all cars in both list as one list
List union
= Stream.concat(bigCarList.stream(), smallCarList.stream()).distinct().collect(Collectors.toList());
List intersect = union.stream().collect(inter);
//Get all cars that only exist not exists in both Lists
List symmetricDifference = union.stream().collect(symDiff);
System.out.println("Union Cars:");
union.stream().forEach(car -> System.out.println("Car: " + car));
System.out.println("");
System.out.println("Intersect Cars: ");
intersect.stream().forEach(car -> System.out.println("Car: " + car));
System.out.println("");
System.out.println("Symmetric Difference: ");
symmetricDifference.stream().forEach(car -> System.out.println("Car: " + car));
System.out.println("");
}
public Collector, ArrayList> produceCollector(Predicate predicate) {
Collector, ArrayList> collector = Collector.of(
ArrayList::new,
(al, car) -> {
if (predicate.test(car)) {
al.add(car);
}
},
(al1, al2) -> {
al1.addAll(al2);
return al1;
}
);
return collector;
}
After doing some research, it seems that the collector is about 14 times faster than a first filter solution.
long before2 = System.nanoTime();
List intersect2 = union.stream().filter(car -> {
return bigCarList.contains(car) && smallCarList.contains(car);
}).collect(Collectors.toList());
long after2 = System.nanoTime();
System.out.println("Time for first filter solution: " + (after2 - before2));
long before = System.nanoTime();
List intersect = union.stream().collect(inter);
long after = System.nanoTime();
System.out.println("Time for collector solution: " + (after - before));
Time for first filter solution: 540906
Time for collector solution: 37543