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.
How can I compare two lists of objects of the same size
java - Comparing a list of objects - Stack Overflow
Best way to compare Two Lists of Objects in Java - Stack Overflow
Best way to compare two lists of objects
Videos
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
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.
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 \$O(n)\$ 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 \$O(\log n)\$ time.
Use a hashset: you can find if an element is in the set in constant time, \$O(1)\$
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;
}
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!
The “different member variables” is irrelevant. It’s an implementation detail. What you need is a set of rules which of two people comes first.
You could for example sort by family name, then given name, then date of birth, and if these are all three equal, take the name of the school, university or company (which will be different member variables) and compare them as strings. If that is equal, you might have student and employee ids, and the student ids might be unique, and the employee ids might be unique, but student and employee ids might be the same. So you could sort then students first ordered by id, followed by employees sorted by id, if you might sort by if first if student and employee ids are comparable.
(University or school and employer might be the same, because universities are also employers).
Comparing objects with different fields sounds like bad polymorphic design, whether it's Java or any other OOP language:
- If your comparator needs to know the precise subtype of an object to do the comparison, you mess-up with the the open-closed principle, since for every new subclassing, you'd potentially need to modify the comparator to select the relevant fields.
- If your comparator needs uses reflexion to find on its own the relevant fields to compare, you indirectly mess up with the principle of encapsulation, since you create a hidden requirement that information to be compared must be in some predetermined field.
If you want to sort People properly in a clean polymorphic design:
- you need to rely either on a field, available for any kind of
People, includingStudent, or - you may call some function/transformation that provides a unique value (e.g. a string) that allows to sort any
People.PeopleandStudentmay then just use a different transformation that will be passed to the comparator; Or - you only sort among homogeneous subtypes.
EDIT
Here are two versions. One using ArrayList and other using HashSet
Compare them and create your own version from this, until you get what you need.
This should be enough to cover the:
P.S: It is not a school assignment :) So if you just guide me it will be enough
part of your question.
continuing with the original answer:
You may use a java.util.Collection and/or java.util.ArrayList for that.
The retainAll method does the following:
Retains only the elements in this collection that are contained in the specified collection
see this sample:
import java.util.Collection;
import java.util.ArrayList;
import java.util.Arrays;
public class Repeated {
public static void main( String [] args ) {
Collection listOne = new ArrayList(Arrays.asList("milan","dingo", "elpha", "hafil", "meat", "iga", "neeta.peeta"));
Collection listTwo = new ArrayList(Arrays.asList("hafil", "iga", "binga", "mike", "dingo"));
listOne.retainAll( listTwo );
System.out.println( listOne );
}
}
EDIT
For the second part ( similar values ) you may use the removeAll method:
Removes all of this collection's elements that are also contained in the specified collection.
This second version gives you also the similar values and handles repeated ( by discarding them).
This time the Collection could be a Set instead of a List ( the difference is, the Set doesn't allow repeated values )
import java.util.Collection;
import java.util.HashSet;
import java.util.Arrays;
class Repeated {
public static void main( String [] args ) {
Collection<String> listOne = Arrays.asList("milan","iga",
"dingo","iga",
"elpha","iga",
"hafil","iga",
"meat","iga",
"neeta.peeta","iga");
Collection<String> listTwo = Arrays.asList("hafil",
"iga",
"binga",
"mike",
"dingo","dingo","dingo");
Collection<String> similar = new HashSet<String>( listOne );
Collection<String> different = new HashSet<String>();
different.addAll( listOne );
different.addAll( listTwo );
similar.retainAll( listTwo );
different.removeAll( similar );
System.out.printf("One:%s%nTwo:%s%nSimilar:%s%nDifferent:%s%n", listOne, listTwo, similar, different);
}
}
Output:
$ java Repeated
One:[milan, iga, dingo, iga, elpha, iga, hafil, iga, meat, iga, neeta.peeta, iga]
Two:[hafil, iga, binga, mike, dingo, dingo, dingo]
Similar:[dingo, iga, hafil]
Different:[mike, binga, milan, meat, elpha, neeta.peeta]
If it doesn't do exactly what you need, it gives you a good start so you can handle from here.
Question for the reader: How would you include all the repeated values?
You can try intersection() and subtract() methods from CollectionUtils.
intersection() method gives you a collection containing common elements and the subtract() method gives you all the uncommon ones.
They should also take care of similar elements