Java: list1=list2 // list1==list2? - java

what does list1=list2 and list1==list2 mean when we use ArrayLists?
ArrayList <String> list1, list2;
list1=new ArrayList<>(); list2=new ArrayList<>();

In Java, a single equal sign = is used to assign values to variables to be used later in your code, this is why it is called the assignment operator.
Two equal signs == is a comparative operation between two values which returns a Boolean. For instance 1 == 1 will return true, but I would be careful when using this operation with objects and would suggest using the equals() or compare() method.

Related

List.equals is false despite all objects in list being equal

I have a list of objects, say Article, which is quite a complex, nested object. I will omit the actual class as it shouldn't matter really; it is probably important to know that Article has equals() implemented (with AutoValue).
I have two lists:
List<Article> list1 = getSomeArticles();
List<Article> list2 = getOtherArticles();
Now I check if they are equal:
boolean listsAreEqual = list1.equals(list2);
this returns false.
But I check if a. both lists have the same size and b. each item at index i is equal in both lists:
if (list1.size() != list2.size()) {
return;
}
for (int i = 0; i < list1.size(); i++) {
Article article1 = list1.get(i);
Article article2 = list2.get(i);
if (!article1.equals(article2)) {
return;
}
}
// All items in the two lists are equals, but list2.equals(list2) is false
Both lists seem to contain exactly the same items, but list1.equals(list2) returns false.
How can that be?
They should be equal. Something is not right with your code. From the documentation:
Compares the specified object with this list for equality. Returns
true if and only if the specified object is also a list, both lists
have the same size, and all corresponding pairs of elements in the two
lists are equal. (Two elements e1 and e2 are equal if (e1==null ?
e2==null : e1.equals(e2)).) In other words, two lists are defined to
be equal if they contain the same elements in the same order. This
definition ensures that the equals method works properly across
different implementations of the List interface.
Unless, of course, the List implementation overrides the default from java.util.List.

Java Check if two lists are mutually exclusive

Ok, I have List a and List b
is there a way to check that no value exist between the two?
List a // 1,2,4,5
List B // 1,6,7,8
Between both list // 1 FAILURE
Collections.disjoint(list1, list2)
returns true if they have no elements in common.
Use Collections.disjoint.
Returns true if the two specified collections have no elements in
common
boolean hasCommonElements = Collections.disjoint(listA, listB);
You can use Collections.disjoint():
public static boolean disjoint(Collection c1, Collection c2): Returns true if the two specified collections have no elements in common.
Code:
List<Integer> a = new ArrayList<Integer>();
List<Integer> b = new ArrayList<Integer>();
System.out.println(Collections.disjoint(a, b));
You have to user Collections.disjoint(a, b);
It returns a boolean: true if the lists have no elements in common.

How to check if ArrayList<ArrayList<String>> contains a certain ArrayList<String>

The title sheds good light on the trouble I am having, here is my code:
// fields required for traversal
private Queue<ArrayList<String>> q;
private ArrayList<ArrayList<String>> r;
Set<String> stringList = getMeStrings();
for(String s : stringList)
{
ArrayList<String> stringsRoute = new ArrayList<String>();
stringsRoute.add(getSomeString());
stringsRoute.add(s);
if(!r.contains(stringList))
{
if(!q.contains(stringList))
{
q.add(stringList);
}
r.add(stringList);
}
}
My If statement inside the For loop always fails, and I think the reason is because I am creating a new ArrayList object (different reference) and my If statement isn't checking to see if the contents of each of the ArrayLists in [ r ] contain the same elements in same order .. etc
I know one needs to use .equals in order to find out if two ArrayLists are similiar, but I have an ArrayList that houses many other ArrayLists.
How can I check if the parent ArrayList contains an ArrayList that equates to the new ArrayList I am creating?
I hope it is clear what I am trying to achieve.
Thanks
you need to traverse the whole ArrayList and then compare each element of the ArrayList with StringsRoute using equals method of ArrayList class.
To implement the foreach loop you could consider getting the size of ArrayList. If we have ArrayList ar=new ArrayList(); we can user ar.size() to return the size and then simply run a for loop ar.size() times to iterate each element in the corressponding ArrayList.
Hopefully that solves your problem.
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/AbstractList.html#equals%28java.lang.Object%29
For "StringsRoute" to be contained in "r" , there must be a list in "r" with the same elements in the same order.
Arrays.asList("1","2") .equals(Arrays.asList("2","1")) == false
Arrays.asList("1","2") .equals(Arrays.asList("1","2")) == true
Arrays.asList(Arrays.asList("1","2")).contains(Arrays.asList("1","2")) == true
Arrays.asList(Arrays.asList("1","2")).contains(Arrays.asList("2","1")) == false
May be you want to use a list of sets to avoid struggling with order.
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/AbstractSet.html#equals%28java.lang.Object%29
List< Set< String > > r;
Since:
new HashSet(Arrays.asList("1","2")).equals(new HashSet(Arrays.asList("2","1"))) == true

Cross compare ArrayList elements and remove duplicates

I have an ArrayList<MyObject> that may (or may not) contain duplicates of MyObject I need to remove from the List. How can I do this in a way that I don't have to check duplication twice as I would do if I were to iterate the list in two for-loops and cross checking every item with every other item.
I just need to check every item once, so comparing A:B is enough - I don't want to compare B:A again, as I already did that.
Furthermore; can I just remove duplicates from the list while looping? Or will that somehow break the list and my loop?
Edit: Okay, I forgot an important part looking through the first answers: A duplicate of MyObject is not just meant in the Java way meaning Object.equals(Object), but I need to be able to compare objects using my own algorithm, as the equality of MyObjects is calculated using an algorithm that checks the Object's fields in a special way that I need to implement!
Furthermore, I can't just override euqals in MyObject as there are several, different Algorithms that implement different strategies for checking the equality of two MyObjects - e.g. there is a simple HashComparer and a more complex EuclidDistanceComparer, both being AbstractComparers implementing different algorithms for the public abstract boolean isEqual(MyObject obj1, MyObject obj2);
Sort the list, and the duplicates will be adjacent to each other, making them easy to identify and remove. Just go through the list remembering the value of the previous item so you can compare it with the current one. If they are the same, remove the current item.
And if you use an ordinary for-loop to go through the list, you control the current position. That means that when you remove an item, you can decrement the position (n--) so that the next time around the loop will visit the same position (which will now be the next item).
You need to provide a custom comparison in your sort? That's not so hard:
Collections.sort(myArrayList, new Comparator<MyObject>() {
public int compare(MyObject o1, MyObject o2) {
return o1.getThing().compareTo(o2.getThing());
}
});
I've written this example so that getThing().compareTo() stands in for whatever you want to do to compare the two objects. You must return an integer that is zero if they are the same, greater than 1 if o1 is greater than o2 and -1 if o1 is less than o2. If getThing() returned a String or a Date, you'd be all set because those classes have a compareTo method already. But you can put whatever code you need to in your custom Comparator.
Create a set and it will remove the duplicates automatically for you if the ordering is not important.
Set<MyObject> mySet = new HashSet<MyObject>(yourList);
Instantiate a new set-based collection HashSet. Don't forget to implement equals and hashcode for MyObject.
Good Luck!
If object order is insignificant
If the order is not important, you can put the elements of the list into a Set:
Set<MyObject> mySet = new HashSet<MyObject>(yourList);
The duplicates will be removed automatically.
If object order is significant
If ordering is significant, then you can manually check for duplicates, e.g. using this snippet:
// Copy the list.
ArrayList<String> newList = (ArrayList<String>) list.clone();
// Iterate
for (int i = 0; i < list.size(); i++) {
for (int j = list.size() - 1; j >= i; j--) {
// If i is j, then it's the same object and don't need to be compared.
if (i == j) {
continue;
}
// If the compared objects are equal, remove them from the copy and break
// to the next loop
if (list.get(i).equals(list.get(j))) {
newList.remove(list.get(i));
break;
}
System.out.println("" + i + "," + j + ": " + list.get(i) + "-" + list.get(j));
}
}
This will remove all duplicates, leaving the last duplicate value as original entry. In addition, it will check each combination only once.
Using Java 8
Java Streams makes it even more elegant:
List<Integer> newList = oldList.stream()
.distinct()
.collect(Collectors.toList());
If you need to consider two of your objects equal based on your own definition, you could do the following:
public static <T, U> Predicate<T> distinctByProperty(Function<? super T, ?> propertyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(propertyExtractor.apply(t));
}
(by Stuart Marks)
And then you could do this:
List<MyObject> newList = oldList.stream()
.filter(distinctByProperty(t -> {
// Your custom property to use when determining whether two objects
// are equal. For example, consider two object equal if their name
// starts with the same character.
return t.getName().charAt(0);
}))
.collect(Collectors.toList());
Futhermore
You cannot modify a list while an Iterator (which is usually used in a for-each loop) is looping through an array. This will throw a ConcurrentModificationException. You can modify the array if you are looping it using a for loop. Then you must control the iterator position (decrementing it while removing an entry).
Or http://docs.oracle.com/javase/6/docs/api/java/util/SortedSet.html if you need sort-order..
EDIT: What about deriving from http://docs.oracle.com/javase/6/docs/api/java/util/TreeSet.html, it will allow you to pass in a Comparator at construction time. You override add() to use your Comparator instead of equals() - this will give you the flexibility of creating different sets that are ordered according to your Comparator and they will implement your "Equality"-Strategy.
Dont forget about equals() and hashCode() though...

Using contains on an ArrayList with integer arrays

I have an ArrayList<int[]>, and I add an array to it.
ArrayList<int[]> j = new ArrayList<int[]>();
int[] w = {1,2};
j.add(w);
Suppose I want to know if j contains an array that has {1,2} in it without using w, since I will be calling it from another class. So, I create a new array with {1,2} in it...
int[] t = {1,2};
return j.contains(t);
...but this would return false even though w was added to the list, and w contains the exact same array as t.
Is there a way to use contains such that I can just check to see if one of the elements of the ArrayList has the array value {1,2}?
Arrays can only be compared with Arrays.equals().
You probably want an ArrayList of ArrayLists.
ArrayList<ArrayList<Integer>> j = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> w = new ArrayList<Integer>();
w.add(1); w.add(2);
j.add(w);
ArrayList<Integer> t = new ArrayList<Integer>();
t.add(1); t.add(2);
return j.contains(t); // should return true.
The problem here is that arrays don't override Object.equals(Object), So the comparison between two list entries happens with the default equals() implementation
// from Object.class
public boolean equals(Object obj) {
return (this == obj);
}
So you have to iterate over the list and check all entries using Arrays.equals(int[], int[]). Here's a Helper method that does this:
public static boolean isInList(
final List<int[]> list, final int[] candidate){
for(final int[] item : list){
if(Arrays.equals(item, candidate)){
return true;
}
}
return false;
}
Update: Ever since Java 8, this has got a lot simpler:
public static boolean isInList(
final List<int[]> list, final int[] candidate) {
return list.stream().anyMatch(a -> Arrays.equals(a, candidate));
// ^-- or you may want to use .parallelStream() here instead
}
You need to iterate through the list and manually check whether an array matches your criteria.
public static boolean containsSubArray(List<int[]> j, int[] sub) {
for ( int[] arr : j ) {
if (arr contains elements of sub) {
return true;
}
}
return false;
}
If you want an exact match, you can make use of Arrays.equals(). I don't think there's a library function to do a contains all on an array though, so you would have to write that yourself if that's what you wanted.
"contains" contract checks for equality. So in your case what is failing is equality of int[]. Since Array does not override the equals method from Object you will need a workaround to check for containment.
If you need to check for containment within the Array then you are left with no choice but to iterate through the ArrayList and do the comparison yourself.
from java api:
public boolean contains(Object o)
Returns true if this list contains the
specified element. More formally,
returns true if and only if this list
contains at least one element e such
that (o==null ? e==null : o.equals(e)).
since int[] is a primitive, im pretty sure no .equals method exists so its my guess it would always return false.
I would recommend a different way of storing the data? maybe with a key of some sort?
Two java array arrays are equal iff they have the same object reference. Content doesn't matter.
You're looking for a way to check if they have an equal content. This could help:
Arrays.equals(new int[]{1,2}, new int[]{1,2}); // evaluates to true
Arrays.equals(new int[]{1,2}, new int[]{2,1}); // evaluates to false (!)
If order shouldn't affect equality, then you will have to implement a static equals method by yourself.
First they are not the same Object reference, so they are not equal. equals() will return false.
For your condition, you will need to implement a method to compare them yourself.
If you have one array and want to compare that all elements of array are present in list:
Long[] array1 = {1111L, 1112L};
Long[] array2 = {1111L, 1114L};
List<Long> list = new ArrayList<>();
list.add(1111L);
list.add(1112L);
list.add(1113L);
Arrays.asList(array1).stream().allMatch(val -> list.contains(val)); //return true
Arrays.asList(array2).stream().allMatch(val -> list.contains(val)); //return false

Categories