6

I have two lists A and B. both have millions of elements. I want to compare and get all elements those are in list A but not in list B. Below is inefficient way to get elements.

   if (!B.containsAll(A)) {
        for (Integer id : A) {
            if (!B.contains(id)) {
                System.out.println(id);
            }
        }
    }

I looking for an efficient way with or without streams to get elements

help is appreciated in this regards.

Thanks

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
  • 2
    Use sets. [Hashsets](https://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html) can check containment very quickly. – khelwood Nov 05 '18 at 14:05
  • Possible duplicate of [iterating and filtering two lists using java 8](https://stackoverflow.com/questions/29490418/iterating-and-filtering-two-lists-using-java-8) – rogerdpack May 24 '19 at 17:00

2 Answers2

2

You don't need to compare

List<Integer> c = new ArrayList<>(a);
c.removeAll(b);

And if you don't mind loosing the original list data

a.removeAll(b);
Guy
  • 46,488
  • 10
  • 44
  • 88
  • 1
    Depending on the sizes of the input lists it might be more efficient to create a `Set` instead of an `ArrayList` (but not necessarily, see https://stackoverflow.com/questions/28671903/hashset-removeall-method-is-surprisingly-slow). Either way, while this is a simple and readable approach, it first creates a full copy of a list containing "millions of elements". – Hulk Nov 05 '18 at 14:18
  • @Hulk It isn't necessary to create the copy if you don't mind loosing the original list. – Guy Nov 05 '18 at 14:34
1

Something like this should suffice:

Set<Integer> container = new HashSet<>(ListB);
ListA.stream()
     .filter(id -> !container.contains(id))
     .forEach(System.out::println);

or non-stream:

Set<Integer> container = new HashSet<>(ListB);
for(Integer id : ListA)
    if(!container.contains(id));
       System.out.println(id);
Ousmane D.
  • 54,915
  • 8
  • 91
  • 126