How can I return the difference between two lists?
JavaListObjectFilteringJava Problem Overview
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
Java Solutions
Solution 1 - Java
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);
Solution 2 - Java
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.
Solution 3 - Java
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"]
Solution 4 - Java
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]
Solution 5 - Java
You can use CollectionUtils from Apache Commons Collections 4.0:
new ArrayList<>(CollectionUtils.subtract(a, b))
Solution 6 - Java
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.
Solution 7 - Java
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());
Solution 8 - Java
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;
}
Solution 9 - Java
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]
}
}
Solution 10 - Java
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]
Solution 11 - Java
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)
Solution 12 - Java
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.