How can I calculate the difference between two ArrayLists?

I have two ArrayLists.

ArrayList A contains:

['2009-05-18','2009-05-19','2009-05-21']

ArrayList B contains:

['2009-05-18','2009-05-18','2009-05-19','2009-05-19','2009-05-20','2009-05-21','2009-05-21','2009-05-22']

I have to compare ArrayList A and ArrayList B. The result ArrayList should contain the List which does not exist in ArrayList A.

ArrayList result should be:

['2009-05-20','2009-05-22']

how to compare ?

150929 次浏览

EDIT: Original question did not specify language. My answer is in C#.

You should instead use HashSet for this purpose. If you must use ArrayList, you could use the following extension methods:

var a = arrayListA.Cast<DateTime>();
var b = arrayListB.Cast<DateTime>();
var c = b.Except(a);


var arrayListC = new ArrayList(c.ToArray());

using HashSet...

var a = new HashSet<DateTime>(); // ...and fill it
var b = new HashSet<DateTime>(); // ...and fill it
b.ExceptWith(a); // removes from b items that are in a

I guess you're talking about C#. If so, you can try this

    ArrayList CompareArrayList(ArrayList a, ArrayList b)
{
ArrayList output = new ArrayList();
for (int i = 0; i < a.Count; i++)
{
string str = (string)a[i];
if (!b.Contains(str))
{
if(!output.Contains(str)) // check for dupes
output.Add(str);
}
}
return output;
}

In Java, you can use the Collection interface's removeAll method.

// Create a couple ArrayList objects and populate them
// with some delicious fruits.
Collection firstList = new ArrayList() \{\{
add("apple");
add("orange");
}};


Collection secondList = new ArrayList() \{\{
add("apple");
add("orange");
add("banana");
add("strawberry");
}};


// Show the "before" lists
System.out.println("First List: " + firstList);
System.out.println("Second List: " + secondList);


// Remove all elements in firstList from secondList
secondList.removeAll(firstList);


// Show the "after" list
System.out.println("Result: " + secondList);

The above code will produce the following output:

First List: [apple, orange]
Second List: [apple, orange, banana, strawberry]
Result: [banana, strawberry]

You are just comparing strings.

Put the values in ArrayList A as keys in HashTable A.
Put the values in ArrayList B as keys in HashTable B.

Then, for each key in HashTable A, remove it from HashTable B if it exists.

What you are left with in HashTable B are the strings (keys) that were not values in ArrayList A.

C# (3.0) example added in response to request for code:

List<string> listA = new List<string>{"2009-05-18","2009-05-19","2009-05-21'"};
List<string> listB = new List<string>{"2009-05-18","2009-05-18","2009-05-19","2009-05-19","2009-05-20","2009-05-21","2009-05-21","2009-05-22"};


HashSet<string> hashA = new HashSet<string>();
HashSet<string> hashB = new HashSet<string>();


foreach (string dateStrA in listA) hashA.Add(dateStrA);
foreach (string dateStrB in listB) hashB.Add(dateStrB);


foreach (string dateStrA in hashA)
{
if (hashB.Contains(dateStrA)) hashB.Remove(dateStrA);
}


List<string> result = hashB.ToList<string>();

You already have the right answer. And if you want to make more complicated and interesting operations between Lists (collections) use apache commons collections (CollectionUtils) It allows you to make conjuction/disjunction, find intersection, check if one collection is a subset of another and other nice things.

Hi use this class this will compare both lists and shows exactly the mismatch b/w both lists.

import java.util.ArrayList;
import java.util.List;




public class ListCompare {


/**
* @param args
*/
public static void main(String[] args) {
List<String> dbVinList;
dbVinList = new ArrayList<String>();
List<String> ediVinList;
ediVinList = new ArrayList<String>();


dbVinList.add("A");
dbVinList.add("B");
dbVinList.add("C");
dbVinList.add("D");


ediVinList.add("A");
ediVinList.add("C");
ediVinList.add("E");
ediVinList.add("F");
/*ediVinList.add("G");
ediVinList.add("H");
ediVinList.add("I");
ediVinList.add("J");*/


List<String> dbVinListClone = dbVinList;
List<String> ediVinListClone = ediVinList;


boolean flag;
String mismatchVins = null;
if(dbVinListClone.containsAll(ediVinListClone)){
flag = dbVinListClone.removeAll(ediVinListClone);
if(flag){
mismatchVins = getMismatchVins(dbVinListClone);
}
}else{
flag = ediVinListClone.removeAll(dbVinListClone);
if(flag){
mismatchVins = getMismatchVins(ediVinListClone);
}
}
if(mismatchVins != null){
System.out.println("mismatch vins : "+mismatchVins);
}


}


private static String getMismatchVins(List<String> mismatchList){
StringBuilder mismatchVins = new StringBuilder();
int i = 0;
for(String mismatch : mismatchList){
i++;
if(i < mismatchList.size() && i!=5){
mismatchVins.append(mismatch).append(",");
}else{
mismatchVins.append(mismatch);
}
if(i==5){
break;
}
}
String mismatch1;
if(mismatchVins.length() > 100){
mismatch1 = mismatchVins.substring(0, 99);
}else{
mismatch1 = mismatchVins.toString();
}
return mismatch1;
}


}

I have used Guava Sets.difference.

The parameters are sets and not general collections, but a handy way to create sets from any collection (with unique items) is Guava ImmutableSet.copyOf(Iterable).

(I first posted this on a related/dupe question, but I'm copying it here too since I feel it is a good option that is so far missing.)

THIS WORK ALSO WITH Arraylist

    // Create a couple ArrayList objects and populate them
// with some delicious fruits.
ArrayList<String> firstList = new ArrayList<String>() {/**
*
*/
private static final long serialVersionUID = 1L;


{
add("apple");
add("orange");
add("pea");
}};


ArrayList<String> secondList = new ArrayList<String>() {


/**
*
*/
private static final long serialVersionUID = 1L;


{
add("apple");
add("orange");
add("banana");
add("strawberry");
}};


// Show the "before" lists
System.out.println("First List: " + firstList);
System.out.println("Second List: " + secondList);


// Remove all elements in firstList from secondList
secondList.removeAll(firstList);


// Show the "after" list
System.out.println("Result: " + secondList);

Although this is a very old question in Java 8 you could do something like

 List<String> a1 = Arrays.asList("2009-05-18", "2009-05-19", "2009-05-21");
List<String> a2 = Arrays.asList("2009-05-18", "2009-05-18", "2009-05-19", "2009-05-19", "2009-05-20", "2009-05-21","2009-05-21", "2009-05-22");


List<String> result = a2.stream().filter(elem -> !a1.contains(elem)).collect(Collectors.toList());

In Java 8 with streams, it's pretty simple actually. EDIT: Can be efficient without streams, see lower.

List<String> listA = Arrays.asList("2009-05-18","2009-05-19","2009-05-21");
List<String> listB = Arrays.asList("2009-05-18","2009-05-18","2009-05-19","2009-05-19",
"2009-05-20","2009-05-21","2009-05-21","2009-05-22");


List<String> result = listB.stream()
.filter(not(new HashSet<>(listA)::contains))
.collect(Collectors.toList());

Note that the hash set is only created once: The method reference is tied to its contains method. Doing the same with lambda would require having the set in a variable. Making a variable is not a bad idea, especially if you find it unsightly or harder to understand.

You can't easily negate the predicate without something like this utility method (or explicit cast), as you can't call the negate method reference directly (type inference is needed first).

private static <T> Predicate<T> not(Predicate<T> predicate) {
return predicate.negate();
}

If streams had a filterOut method or something, it would look nicer.


Also, @Holger gave me an idea. ArrayList has its removeAll method optimized for multiple removals, it only rearranges its elements once. However, it uses the contains method provided by given collection, so we need to optimize that part if listA is anything but tiny.

With listA and listB declared previously, this solution doesn't need Java 8 and it's very efficient.

List<String> result = new ArrayList(listB);
result.removeAll(new HashSet<>(listA));