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.
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.
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.
Comparing two list of objects in Java - Stack Overflow
java - Determine if 2 lists with similar objects contain a partial duplicate - Code Review Stack Exchange
How can I compare two lists of objects of the same size
comparator - Compare two List of Objects in Java - Stack Overflow
I would suggest you the retainAll method:
List<Student> listC = new ArrayList();
listC.addAll(listA);
listC.retainAll(listB); //now listC contains all double students
But you should still override the equals method
You could use containsAny method from CollectionUtils (Apache Commons):
if(CollectionUtils.containsAny(listA, listB)){
break;
}
The approach, algorithm
To find if an object exists in a list, you need to perform a linear search,
potentially visiting every single element, in \ time.
More efficient data structures exist:
Use an ordered data structure: if the values are sorted, then you can find if an element exists using binary search, in \
time.
Use a hashset: you can find if an element is in the set in constant time, \
To be to search efficiently, use a hashset instead of a list.
However, to be able to use a hashset efficiently,
it is required that the objects you put in it have appropriate implementation of hashCode and equals methods.
See the official tutorial on the Object class,
especially the sections on the equals and hashCode methods.
Note that IDEs like IntelliJ and Eclipse can generate these methods for you easily (they are boring to write by hand, and usually there's little reason to do so).
With correct implementation of the equals and hashCode methods,
for example as in the other answer by @Teddy,
your main program could be reduced to this:
public static void main(String[] args) {
Set<Person> originalPeople = new HashSet<>();
Set<Person> newPeople = new HashSet<>();
originalPeople.add(new Person("William", "Tyndale"));
originalPeople.add(new Person("Jonathan", "Edwards"));
originalPeople.add(new Person("Martin", "Luther"));
newPeople.add(new Person("Jonathan", "Edwards"));
newPeople.add(new Person("James", "Tyndale"));
newPeople.add(new Person("Roger", "Moore"));
for (Person original : originalPeople) {
if (!newPeople.contains(original)) {
System.out.printf("%s %s is not in the new list!%n",
original.getFirstName(), original.getLastName());
}
}
}
There are certain reasons I would not prefer your approach. These are:
1) There are multiple method calls which reduces the readability.
2) You are using filter twice which decreases the performances. You could do it inside the same filter like I've shown below
3) With this approach you don't have a consolidated List which contains common elements. For that you need another else condition which increases the cyclomatic complexity.
4) A null check which could produce NPE if not handled carefully as you are using findFirst() which returns Optional (Although null can be replaced with default new Person("","") object which is again not recommended).
5) Finally don't use ArrayList<Person> originalPeople = new ArrayList<>();; rather declare as List, to follow programming to interface.
Rather I would use below approach:
private static List<Person> getPersonInList(
final List<Person> newPeople, List<Person> originalPeople) {
List<Person> list = new ArrayList<>();
newPeople.forEach(p ->
originalPeople.stream()
.filter(p1 -> p.getFirstName().equals(p1.getFirstName()) &&
p.getLastName().equals(p1.getLastName()))
.forEach(list::add));
return list;
}
I want to do a certain action each time an object is the same and at the same index and another action each time an object is present in both lists but not at the same index. It has to match though (i cant do the second action 4 times if both lists are like that ex :(r,f,f,f,f) (r, r, r, r, r) only once
Can I sort two arraylists containing objects so that I can compare them and their contents? I tried to type in:
Collections.sort.myArrayList but it wouldnt work!
Use Assert.assertArrayEquals(Object[] expecteds, Object[] actuals) method to compare two array for content equality:
Assert.assertArrayEquals(expected.toArray(), actuals.toArray());
equals method compares arrays for being the same reference so it's not suitable in test cases.
For your other question: Remember to use org.junit.Assert not junit.Assert which became obsolete.
In short: there is exactly one assert that one needs when writing JUnit tests: assertThat
You just write code like
assertThat("optional message printed on fails", actualArrayListWhatever, is(expectedArrayListWhatever))
where is() is a hamcrest matcher.
This approach does work for all kinds of collections and stuff; and it does the natural "compare element by element" thing (and there are plenty of other hamcrest matcher that one can use for more specific testing; and it is also pretty easy to write your own matchers).
( seriously; I have not seen a single case where assertThat() would not work; or would result in less readable code )
Override the equals and hashcode method based on first five keys. Then you can just use equals method to compare the objects and use Collections bulk operations like retainAll etc.
You could overwrite Equals and HashCode of CustomObj. Then use Contains() to test uniqueness.
Try using Apache Commons isEqualCollection(Collection a, Collection b, Equator equator), you will still need to implement Equator in the same way you would write a equals override.
You could try this one too, this is the same algorithm from Apache Commons but with some performance improvements.
Point 1: See Kayaman's comment (wrapper class providing equals function).
Point 2: This wrapper class might additionally provide a lessThan function imposing an absolute order on the elements. You then could sort both lists and afterwards compare them element by element. This is more efficient than trying to identify each element of one list in the other one and additionally handles problems with duplicates elegantly.
Implementation examples for e. g. quicksort can be found all over the internet, e. g. here.
I don't know of any cleaner way than what you already suggest.
However, if you need equality but can't use equals (I'm not going to ask ;) you could merge the lists and sort them, and then compare manually each element to the next, keeping only the duplicate ones.
If you want to get the same value from two list, I give you a string example:
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// create a script engine manager
List<String> list_1 = new ArrayList<String>();
list_1.add("a");
list_1.add("b");
List<String> list_2 = new ArrayList<String>();
list_2.add("a");
list_2.add("b");
list_2.add("c");
System.out.println(getSameVaue(list_2,list_1));
}
public static List<String> getSameVaue(List<String> list1,
List<String> list2) {
List<String> result = new ArrayList<String>();
if (list1.size() > list2.size()) {
for (String s : list1) {
if (list2.contains(s)) {
result.add(s);
}
}
} else {
for (String s : list2) {
if (list1.contains(s)) {
result.add(s);
}
}
}
return result;
}
But if you want to use your Object, please do not forget implement equals method.