81

I have two array lists e.g.

List<Date> a;
contains : 10/10/2014, 10/11/2016

List<Date> b;
contains : 10/10/2016

How can i do a check between list a and b so the value that is missing in b is returned?e.g. 10/10/2014

TylerH
  • 20,799
  • 66
  • 75
  • 101
Rory Lester
  • 2,858
  • 11
  • 49
  • 66

12 Answers12

77

You can convert them to Set collections, and perform a set difference operation on them.

Like this:

Set<Date> ad = new HashSet<Date>(a);
Set<Date> bd = new HashSet<Date>(b);
ad.removeAll(bd);
Zoe
  • 27,060
  • 21
  • 118
  • 148
Pablo Santa Cruz
  • 176,835
  • 32
  • 241
  • 292
  • 44
    `removeAll` returns a `boolean` not a `Set` – Lukazoid Aug 26 '15 at 12:33
  • 5
    That's correct, but when you look at the documentation you will see that this boolean informs wether or not "this set changed as a result of the call". After this change you can adres the Set and you'll notice it has the results you expected. – Dennie Apr 13 '16 at 07:24
  • 12
    Creating `bd` `HashSet` is unnecessary. You can just call `ad.removeAll(b)`. – SlavaSt May 17 '18 at 16:43
  • 2
    what if bd has more elements than ad? what happens in that case? – Shivansh Jul 02 '20 at 12:20
49

If you only want find missing values in b, you can do:

List toReturn = new ArrayList(a);
toReturn.removeAll(b);

return toReturn;

If you want to find out values which are present in either list you can execute upper code twice. With changed lists.

Denis Lukenich
  • 3,084
  • 1
  • 20
  • 38
36

I was looking similar but I wanted the difference in either list (uncommon elements between the 2 lists).

Let say I have:

List<String> oldKeys = Arrays.asList("key0","key1","key2","key5");
List<String> newKeys = Arrays.asList("key0","key2","key5", "key6");

And I wanted to know which key has been added and which key is removed i.e I wanted to get (key1, key6)

Using org.apache.commons.collections.CollectionUtils

List<String> list = new ArrayList<>(CollectionUtils.disjunction(newKeys, oldKeys));

Result

["key1", "key6"]
Roshana Pitigala
  • 8,437
  • 8
  • 49
  • 80
justMe
  • 2,200
  • 16
  • 20
  • 1
    Could you point me to the maven repository for the same. I tried this `https://mvnrepository.com/artifact/org.apache.commons/commons-collections4/4.4` But it does not seem to be the right one. – paradocslover Apr 30 '21 at 11:07
  • 1
    @paradocslover it was https://mvnrepository.com/artifact/commons-collections/commons-collections/3.2.2 – justMe Apr 30 '21 at 15:11
  • 1
    Thanks a lot!! Any idea what is the function renamed to in the newer versions of the package? – paradocslover Apr 30 '21 at 16:06
26

You can use filter in the Java 8 Stream library

List<String> aList = List.of("l","e","t","'","s");
List<String> bList = List.of("g","o","e","s","t");

List<String> difference = aList.stream()
    .filter(aObject -> {
        return ! bList.contains(aObject);
      })
    .collect(Collectors.toList());

//more reduced: no curly braces, no return
List<String> difference2 = aList.stream()
    .filter(aObject -> ! bList.contains(aObject))
    .collect(Collectors.toList());

Result of System.out.println(difference);:

[e, t, s]

lue
  • 449
  • 5
  • 16
9

You can use CollectionUtils from Apache Commons Collections 4.0:

new ArrayList<>(CollectionUtils.subtract(a, b))
contrapost
  • 673
  • 12
  • 22
  • 1
    Note: this approach does not support generics in any way, so what you get is a raw, un-checked `Collection` instance. – Per Lundberg Aug 13 '19 at 10:40
  • 1
    The method signature is: `public static Collection subtract(Iterable extends O> a, Iterable extends O> b)`, and according to documentation: "O - the generic type that is able to represent the types contained in both input collections." – contrapost Sep 03 '19 at 14:52
  • You are indeed correct; mea culpa. I was looking at the 3.2 version of the class where the method has a simple `public static Collection subtract(final Collection a, final Collection b)` signature. Great to see that they have improved on this in the 4.0 iteration. – Per Lundberg Sep 04 '19 at 07:00
6

First convert list to sets.

// create an empty set 
Set<T> set = new HashSet<>(); 

// Add each element of list into the set 
for (T t : list) 
    set.add(t); 

You can use Sets.difference(Set1, Set2), which returns extra items present in Set1.
You can use Sets.difference(Set2, Set1), which returns extra items present in Set2.

Pavel Smirnov
  • 4,611
  • 3
  • 18
  • 28
gs manisha
  • 61
  • 1
  • 1
5

With Stream API you can do something like this:

List<String> aWithoutB = a.stream()
    .filter(element -> !b.contains(element))
    .collect(Collectors.toList());

List<String> bWithoutA = b.stream()
    .filter(element -> !a.contains(element))
    .collect(Collectors.toList());

Iskuskov Alexander
  • 4,077
  • 3
  • 23
  • 38
4

Here is a generic solution for this problem.

public <T> List<T> difference(List<T> first, List<T> second) {
    List<T> toReturn = new ArrayList<>(first);
    toReturn.removeAll(second);
    return toReturn;
}
fuat
  • 1,484
  • 2
  • 19
  • 25
1

You may call Underscore.difference(lists) method in underscore-java library. Live example

import com.github.underscore.Underscore;
import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> list1 = Arrays.asList(1, 2, 3);
        List<Integer> list2 = Arrays.asList(1, 2);
        List<Integer> list3 = Underscore.difference(list1, list2);
        System.out.println(list3);
        // [3]
    }
}
Valentyn Kolesnikov
  • 2,029
  • 1
  • 24
  • 31
1
List<String> l1 = new ArrayList<String>();
l1.add("apple");
l1.add("orange");
l1.add("banana");
l1.add("strawberry");

List<String> l2 = new ArrayList<String>();
l2.add("apple");
l2.add("orange");

System.out.println(l1);
System.out.println(l2);

for (String A: l2) {
  if (l1.contains(A))
    l1.remove(A);
}

System.out.println("output");
System.out.println(l1);

Output:

[apple, orange, banana, strawberry]
[apple, orange]
output
[banana, strawberry]
adiga
  • 34,372
  • 9
  • 61
  • 83
0

I was looking for a different problem and came across this, so I will add my solution to a related problem: comparing two Maps.

    // make a copy of the data
    Map<String,String> a = new HashMap<String,String>(actual);
    Map<String,String> e = new HashMap<String,String>(expected);
    // check *every* expected value
    for(Map.Entry<String, String> val : e.entrySet()){
        // check for presence
        if(!a.containsKey(val.getKey())){
            System.out.println(String.format("Did not find expected value: %s", val.getKey()));
        }
        // check for equality
        else{
            if(0 != a.get(val.getKey()).compareTo(val.getValue())){
                System.out.println(String.format("Value does not match expected: %s", val.getValue()));
            }
            // we have found the item, so remove it 
            // from future consideration. While it 
            // doesn't affect Java Maps, other types of sets
            // may contain duplicates, this will flag those
            // duplicates. 
            a.remove(val.getKey());
        }
    }
    // check to see that we did not receive extra values
    for(Map.Entry<String,String> val : a.entrySet()){
        System.out.println(String.format("Found unexpected value: %s", val.getKey()));
    }

It works on the same principle as the other solutions but also compares not only that values are present, but that they contain the same value. Mostly I've used this in accounting software when comparing data from two sources (Employee and Manager entered values match; Customer and Corporate transactions match; ... etc)

Jefferey Cave
  • 2,507
  • 1
  • 27
  • 46
  • I wasn't aware of a question regarding maps. If you have found a question that was asking about maps, do feel free to link to this answer. – Jefferey Cave Feb 01 '18 at 10:54
  • 2
    Answers should address the question asked. If you think you have a useful code snippet / explanation for something where no question exists, ask the question yourself and self-answer it using the built-in site function. Don't post your answer under an unrelated question. – TylerH Aug 19 '19 at 15:10
  • The difference between my answer and the question is not the use of `Map` vs `List`. The difference lies with the question asking only for missing values, I addressed "missing, added, and equality" of values. I would be concerned if an answer seeker could not see the ways in which `Map`, `Set`, and `List` are related concepts. – Jefferey Cave Aug 19 '19 at 20:21
0

Set is a map underneath i was able to get the diff between two list over a million entries each wrapping it in a HashSet this is a simple code to do it.

private List<String>notPresentMethod(final List<String>left,final List<String>right){
    final Set<String>setIsFaster = new HashSet<>(right);
    return left.stream()
            .filter(((Predicate<String>)setIsFaster::contains).negate())
            .collect(Collectors.toList());
}

Using only list took over a hour and did not complete. And using this sample took Just seconds.

chiperortiz
  • 4,751
  • 9
  • 45
  • 79