55

I have two list **ListA<MyData> listA = new ArrayList<MyData>()** and ListB<MyData> listB = new ArrayList<MyData>() both contain object of type MyData and MyData contain these variables.

MyData {
    String name;
    boolean check;
} 

ListA and ListB both contains MyData objects ,now I have to compare both the list's object values here name as well check variable like if ListA contains these object values

ListA = ["Ram",true],["Hariom",true],["Shiv",true];

and ListB also contain

ListB = ["Ram",true],["Hariom",true],["Shiv",true];

then i have to compare lists and return false because both list are same But if ListA contains

ListA = ["Ram",true],["Hariom",true],["Shiv",false];

and ListB Contain

 ListB = ["Ram",true],["Hariom",true],["Shiv",true];

then I have to compare lists and return true because both list are not same

or vice-versa so any slight change in the any list values I have to return true. One thing I have to mentioned here objects can be in any order.

Ani Menon
  • 27,209
  • 16
  • 105
  • 126
  • 2
    I can't differentiate any of the above lists. – Abubakkar Apr 25 '13 at 06:20
  • Objects values are changed one object contain true another false –  Apr 25 '13 at 06:21
  • @askkuber Do you care about the order of both lists at all, e.g. should iterating over them always give the same result? If not, just use a `Set`, e.g. a [`HashSet`](http://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html), [implement `equals()` and `hashCode()`](http://stackoverflow.com/questions/27581/overriding-equals-and-hashcode-in-java) on `MyData` and just compare both sets with `setA.equals(setB)`. – Philipp Reichart Apr 25 '13 at 06:47
  • @Philipp list contain object in any order i have to compare them and return true if any single change found –  Apr 25 '13 at 06:52
  • I suggest sorting them by a good `hashCode()` implementation then comparing pairs of elements to see if they are equal. – Patashu Apr 25 '13 at 06:58
  • @askhuber Can you use a `Set` (unordered, just the contents matter, can not have duplicate elements) instead of `List` (both order and contents matter, can have duplicate elements) for your MyData objects? If not, can your code modify the lists, e.g. by sorting them, or do both lists have to stay the same? – Philipp Reichart Apr 25 '13 at 07:05
  • yes i can apply your changes as well –  Apr 25 '13 at 07:13

15 Answers15

56

It's not the most efficient solution but the most terse code would be:

boolean equalLists = listA.size() == listB.size() && listA.containsAll(listB);

Update:

@WesleyPorter is right. The solution above will not work if duplicate objects are in the collection.
For a complete solution you need to iterate over a collection so duplicate objects are handled correctly.

private static boolean cmp( List<?> l1, List<?> l2 ) {
    // make a copy of the list so the original list is not changed, and remove() is supported
    ArrayList<?> cp = new ArrayList<>( l1 );
    for ( Object o : l2 ) {
        if ( !cp.remove( o ) ) {
            return false;
        }
    }
    return cp.isEmpty();
}

Update 28-Oct-2014:

@RoeeGavriel is right. The return statement needs to be conditional. The code above is updated.

Oded Peer
  • 2,377
  • 18
  • 25
  • 4
    This solution will not work for certain edge cases. For instance if listA = ["1", "blah", "1", "4"] and listB = ["1", "blah", "blah", "4"], the method will return true, when these two lists are indeed different. – Wesley Porter Jul 24 '14 at 15:31
  • 2
    The update will fail and return true if L1 have all items of L2 and some more (L1="1","2","3" & L2="1","2"). it would work if you change the last statement to `return (cp.size()==0);` – Roee Gavirel Oct 27 '14 at 14:35
  • Time complexity: O(n^2) ! – yohm Mar 19 '15 at 21:12
  • With more complex java objects, do we need to override `hashcode()` for this to work? – mal Nov 30 '16 at 10:06
19

ArrayList already have support for this, with the equals method. Quoting the docs

... In other words, two lists are defined to be equal if they contain the same elements in the same order.

It does require you to properly implement equals in your MyData class.

Edit

You have updated the question stating that the lists could have different orders. In that case, sort your list first, and then apply equals.

NilsH
  • 13,705
  • 4
  • 41
  • 59
7

I got this solution for above problem

public boolean compareLists(List<MyData> prevList, List<MyData> modelList) {
        if (prevList.size() == modelList.size()) {
            for (MyData modelListdata : modelList) {
                for (MyData prevListdata : prevList) {
                    if (prevListdata.getName().equals(modelListdata.getName())
                            && prevListdata.isCheck() != modelListdata.isCheck()) {
                        return  true;

                    }
                }

            }
        }
        else{
            return true;
        }
        return false; 

    }

EDITED:-
How can we cover this... Imagine if you had two arrays "A",true "B",true "C",true and "A",true "B",true "D",true. Even though array one has C and array two has D there's no check that will catch that(Mentioned by @Patashu)..SO for that i have made below changes.

public boolean compareLists(List<MyData> prevList, List<MyData> modelList) {
        if (prevList!= null && modelList!=null && prevList.size() == modelList.size()) {
            boolean indicator = false;
            for (MyData modelListdata : modelList) {
                for (MyData prevListdata : prevList) {
                    if (prevListdata.getName().equals(modelListdata.getName())
                            && prevListdata.isCheck() != modelListdata.isCheck()) {
                        return  true;

                    }
                    if (modelListdata.getName().equals(prevListdata.getName())) {
                        indicator = false;
                        break;
                    } else
                        indicator = true;
                }
                }

            }
        if (indicator)
            return true;
    }
        }
        else{
            return true;
        }
        return false; 

    }
  • This will not work if the lists have identical objects but out of order. – Patashu Apr 25 '13 at 06:58
  • @Patashu not tested but it would work because i have two for loops –  Apr 25 '13 at 07:14
  • As long as the lists always have the same names your algorithm should be OK. There's no check to see if they have differing names, just differing amounts of names. – Patashu Apr 25 '13 at 08:06
  • But it work for me can you give details in which criteria it is not working? –  Apr 25 '13 at 08:39
  • Imagine if you had two arrays `"A",true "B",true "C",true and "A",true "B",true "D",true`. Even though array one has C and array two has D there's no check that will catch that. If that kind of scenario will never happen your code is OK, if it can your code is not OK. – Patashu Apr 25 '13 at 10:05
  • Yes thanks i got ur time i will have a look and change my code –  Apr 25 '13 at 10:14
  • thanks answer edited please let me know if you have better idea..thanks –  Apr 25 '13 at 11:19
  • what is isCheck() method here? thats used in a comparison condition? – AKIWEB Mar 03 '17 at 17:12
2

First, implement the MyData.equals(Object o) and MyData.hashCode() methods. Once you implemented the equals method, you can iterate over the lists as follows:

if(ListA == null && ListB == null)
    return false;
if(ListA == null && ListB != null)
    return true;
if(ListA != null && ListB == null)
    return true;
int max = ListA.size() > ListB.size() ? ListA.size() : ListB.size();
for(int i = 0; i < max; i++) {
    myData1 = ListA.get(i);
    myData2 = ListB.get(i);
    if(!myData1.equals(myData2)) {
        return true;
    }
}
return false;
Amir Kost
  • 2,148
  • 1
  • 16
  • 30
  • 2
    Always implement `equals()` *and* `hashCode()` -- implementing only one of them might lose your elements in a collection or just break the collection completely. – Philipp Reichart Apr 25 '13 at 06:48
2

I found a very basic example of List comparison at List Compare This example verifies the size first and then checks the availability of the particular element of one list in another.

Manoj Kumar
  • 111
  • 3
2

This can be done easily through Java8 using forEach and removeIf method.

Take two lists. Iterate from listA and compare elements inside listB

Write any condition inside removeIf method.

Hope this will help

listToCompareFrom.forEach(entity -> listToRemoveFrom.removeIf(x -> x.contains(entity)));
1

Override the equals method in your class and use Collection#equals() method to check for equality.

AllTooSir
  • 48,828
  • 16
  • 130
  • 164
  • 4
    Always implement `equals()` *and* `hashCode()` -- implementing only one of them might lose your elements in a collection or just break the collection completely. – Philipp Reichart Apr 25 '13 at 06:49
1

See if this works.

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


public class ArrayListComparison {

    public static void main(String[] args) {
        List<MyData> list1 = new ArrayList<MyData>();
        list1.add(new MyData("Ram", true));
        list1.add(new MyData("Hariom", true));
        list1.add(new MyData("Shiv", true));
//      list1.add(new MyData("Shiv", false));
        List<MyData> list2 = new ArrayList<MyData>();
        list2.add(new MyData("Ram", true));
        list2.add(new MyData("Hariom", true));
        list2.add(new MyData("Shiv", true));

        System.out.println("Lists are equal:" + listEquals(list1, list2));
    }

    private static boolean listEquals(List<MyData> list1, List<MyData> list2) {
        if(list1.size() != list2.size())
            return true;
        for (MyData myData : list1) {
            if(!list2.contains(myData))
                return true;
        }
        return false;
    }
}

class MyData{
    String name;
    boolean check;


    public MyData(String name, boolean check) {
        super();
        this.name = name;
        this.check = check;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (check ? 1231 : 1237);
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        MyData other = (MyData) obj;
        if (check != other.check)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
} 
krishnakumarp
  • 8,967
  • 3
  • 49
  • 55
1

You can subtract one list from the other using CollectionUtils.subtract, if the result is an empty collection, it means both lists are the same. Another approach is using CollectionUtils.isSubCollection or CollectionUtils.isProperSubCollection.

For any case you should implement equals and hashCode methods for your object.

1

Using java 8 removeIf to compare similar items

public int getSimilarItems(){
    List<String> one = Arrays.asList("milan", "dingo", "elpha", "hafil", "meat", "iga", "neeta.peeta");
    List<String> two = new ArrayList<>(Arrays.asList("hafil", "iga", "binga", "mike", "dingo")); //Cannot remove directly from array backed collection
    int initial = two.size();

    two.removeIf(one::contains);
    return initial - two.size();
}
Asanka Siriwardena
  • 871
  • 13
  • 18
0

Logic should be something like:

  1. First step: For class MyData implements Comparable interface, override the compareTo method as per the per object requirement.

  2. Second step: When it comes to list comparison (after checking for nulls), 2.1 Check the size of both lists, if equal returns true else return false, continue to object iteration 2.2 If step 2.1 returns true, iterate over elements from both lists and invoke something like,

    listA.get(i).compareTo(listB.get(i))

This will be as per the code mentioned in step-1.

Himanshu Bhardwaj
  • 4,038
  • 3
  • 17
  • 36
0

It's been about 5 years since then and luckily we have Kotlin now.
Comparing of two lists now looks is as simple as:

fun areListsEqual(list1 : List<Any>, list2 : List<Any>) : Boolean {
        return list1 == list2
}

Or just feel free to omit it at all and use equality operator.

Leo DroidCoder
  • 14,527
  • 4
  • 62
  • 54
0

I know it's old question but in case anyone needs it. I use this in my application and it works well. i used it to check if the cart has been changed or not.

private boolean validateOrderProducts(Cart cart) {
    boolean doesProductsChanged = false;
    if (originalProductsList.size() == cart.getCartItemsList().size()) {
        for (Product originalProduct : originalProductsList) {
            if (!doesProductsChanged) {
                for (Product cartProduct : cart.getCartProducts()) {
                    if (originalProduct.getId() == cartProduct.getId()) {
                        if (originalProduct.getPivot().getProductCount() != cartProduct.getCount()) {
                            doesProductsChanged = true;
                            // cart has been changed -> break from inner loop
                            break;
                        }
                    } else {
                        doesProductsChanged = false;
                    }
                }
            } else {
                // cart is already changed -> break from first loop
                break;
            }
        }
    } else {
        // some products has been added or removed (simplest case of Change)
        return true;
    }
    return doesProductsChanged;
}
Mohamed Nageh
  • 1,963
  • 1
  • 19
  • 27
0
String myData1 = list1.toString();
String myData2 = list2.toString()

return myData1.equals(myData2);

where :
list1 - List<MyData>
list2 - List<MyData>

Comparing the String worked for me. Also NOTE I had overridden toString() method in MyData class.

abc123
  • 527
  • 5
  • 16
0

I think you can sort both lists and convert to List if some of them was a HashSet colleciton.

java.utils.Collections package lets you do it.

List<Category> categoriesList = new ArrayList<>();
Set<Category> setList = new HashSet<>();
Collections.sort(categoriesList);
List<Category> fileCategories = new ArrayList<>(setList);
Collections.sort(fileCategories);

if(categoriesList.size() == fileCategories.size() && categoriesList.containsAll(fileCategories)) {
    //Do something
}
Víctor
  • 493
  • 5
  • 7