You are right in saying that if they are arrays you can't use Arrays.equals(), if they are List<>s then you cannot just use equals. In both cases they also check order.
So yes your main option without writing your own comparison algorithm is to use Collections.sort() on both lists.
If you don't need to check for duplicates you could drop both lists into a HashSet using addAll and then compare the two HashSet or just use List.containsAll. The bad news though is that these would both have the same limitation, if you need to compare lists that might have repeated elements then it may give incorrect results. i.e. "bob", "bob", "fred" would compare as equal to "bob", "fred", "fred".
You are right in saying that if they are arrays you can't use Arrays.equals(), if they are List<>s then you cannot just use equals. In both cases they also check order.
So yes your main option without writing your own comparison algorithm is to use Collections.sort() on both lists.
If you don't need to check for duplicates you could drop both lists into a HashSet using addAll and then compare the two HashSet or just use List.containsAll. The bad news though is that these would both have the same limitation, if you need to compare lists that might have repeated elements then it may give incorrect results. i.e. "bob", "bob", "fred" would compare as equal to "bob", "fred", "fred".
Please refer to the example below:
public class Example{
public static void main(String[] args){
List<String> list1 = new ArrayList<String>();
List<String> list2 = new ArrayList<String>();
list1.add("A");
list1.add("B");
list1.add("C");
list2.add("C");
list2.add("X");
list2.add("Y");
for(String s : list1){
if(list2.contains(s)){
System.out.println("List 2 contains: " + s);
}
}
}
}
The code above is by all means not the cleanest or the most compact way to achieve what you are asking. But given the information presented, this should suffice.
Convert Lists to Collection and use removeAll
Collection<String> listOne = new ArrayList(Arrays.asList("a","b", "c", "d", "e", "f", "g"));
Collection<String> listTwo = new ArrayList(Arrays.asList("a","b", "d", "e", "f", "gg", "h"));
List<String> sourceList = new ArrayList<String>(listOne);
List<String> destinationList = new ArrayList<String>(listTwo);
sourceList.removeAll( listTwo );
destinationList.removeAll( listOne );
System.out.println( sourceList );
System.out.println( destinationList );
Output:
[c, g]
[gg, h]
[EDIT]
other way (more clear)
Collection<String> list = new ArrayList(Arrays.asList("a","b", "c", "d", "e", "f", "g"));
List<String> sourceList = new ArrayList<String>(list);
List<String> destinationList = new ArrayList<String>(list);
list.add("boo");
list.remove("b");
sourceList.removeAll( list );
list.removeAll( destinationList );
System.out.println( sourceList );
System.out.println( list );
Output:
[b]
[boo]
This should check if two lists are equal, it does some basic checks first (i.e. nulls and lengths), then sorts and uses the collections.equals method to check if they are equal.
public boolean equalLists(List<String> a, List<String> b){
// Check for sizes and nulls
if (a == null && b == null) return true;
if ((a == null && b!= null) || (a != null && b== null) || (a.size() != b.size()))
{
return false;
}
// Sort and compare the two lists
Collections.sort(a);
Collections.sort(b);
return a.equals(b);
}
Don't use != to compare strings. Use the equals method :
if (! Blist.get(i).equals(Alist.get(j))
But this wouldn't probably fix your algorithmic problem (which isn't clear at all).
If what you want is know what items are the same at the same position, you could use a simple loop :
int sizeOfTheShortestList = Math.min(Alist.size(), Blist.size());
for (int i=0; i<sizeOfTheShortestList; i++) {
if (Blist.get(i).equals(Alist.get(i))) {
System.out.println("Equals..: " + Blist.get(i));
}
}
If you want to get items that are in both lists, use
for (int i = 0; i < Alist.size(); i++) {
if (Blist.contains(Alist.get(i))) {
System.out.println("Equals..: " + Alist.get(i));
}
}
You can use the RemoveAll(Collection c) on one of the lists, if you happen to know if one list always contains them all.
You could use isEqualList from Apache's ListUtils:
isEqualList
public static boolean isEqualList(java.util.Collection list1,
java.util.Collection list2)
Tests two lists for value-equality as per the equality contract in List.equals(java.lang.Object).
This method is useful for implementing List when you cannot extend AbstractList. The method takes Collection instances to enable other collection types to use the List implementation algorithm.
The relevant text (slightly paraphrased as this is a static method) is:
Compares the two list objects for equality. Returns true if and only if 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. Note: The behaviour of this method is undefined if the lists are modified during the equals comparison.
It is the correct way. Your lists are not equal as you say they are. Try printing them for visual inspection.
Perhaps the easiest solution would be to use two List<List<String>>s instead. Assuming the List implementations used extend AbstractList, using equals will give you the desired behavior. From the documentation for AbstractList.equals:
Compares the specified object with this list for equality. Returns
trueif 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 elementse1ande2are 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.
You can easily wrap a String[] in a thin List<String> implementation that extends AbstractList by using Arrays.asList.
EDIT: Here's an example:
String[] array1 = {"1", "2", "3"};
String[] array2 = {"4", "7"};
String[] array3 = {"1", "2", "3"};
String[] array4 = {"4", "7"};
List<List<String>> lst1 = new ArrayList<>();
lst1.add(Arrays.asList(array1));
lst1.add(Arrays.asList(array2));
List<List<String>> lst2 = new ArrayList<>();
lst2.add(Arrays.asList(array3));
lst2.add(Arrays.asList(array4));
System.out.println(lst1.equals(lst2)); //prints true
Typically you should avoid dealing with Arrays. they are ugly and lead to these kind of problems. If possible use List<List<String>> then you can use .equals() normally.
if you insist, you could use a custom isequal implementation like below. the key is to use Arrays.equals()
public class DemoEquals {
List<String[]> listOne = (List<String[]>) Arrays.asList(new String[]{"one1", "one2"}, new String[]{"two1"});
List<String[]> listOneOne = (List<String[]>) Arrays.asList(new String[]{"one1", "one2"}, new String[]{"two1"});
List<String[]> listTwo = (List<String[]>) Arrays.asList(new String[]{"2one1", "2one2"}, new String[]{"2two1"});
private boolean isEqual(List<String[]> list1, List<String[]> list2) {
if (list1.size() != list2.size()) return false;
for (int i = 0; i < list1.size(); i++) {
if (!Arrays.equals(list1.get(i), list2.get(i))) return false;
}
return true;
}
@SuppressWarnings("unchecked")
private void isEqual() {
//prints true
System.out.println(isEqual(Collections.EMPTY_LIST, Collections.EMPTY_LIST));
//prints true
System.out.println(isEqual(listOne, listOne));
//prints true
System.out.println(isEqual(listOne, listOneOne));
//prints false
System.out.println(isEqual(listOne, listTwo));
//prints false
System.out.println(isEqual(listOne, Collections.EMPTY_LIST));
}
public static void main(String[] args) {
new DemoEquals().isEqual();
}
}
Use
ArrayList.contains("StringToBeChecked");
If the String is present in the ArrayList, this function will return true, else will return false.
Look at the List#contains(T obj) method, like this:
List<String> list = new ArrayList<String>();
list.add("abc");
list.add("xyz");
list.contains("abc"); // true
list.contains("foo"); // false
Try fnlData.equals(fnlDataTMP) if both list are in order
or if order does not matter, try creating hash set and then compare using equals
new HashSet(fnlData).equals(new HashSet(fnlDataTMP))
I don't think there is a way that let's you achieve that out of the box.
You can do something like the functional java List.join method to quickly generate 2 Lists and compare these:
List<String> joinedFnlData = jf.data.List.join(fnlData);
List<String> joinedFnlDataTMP = jf.data.List.join(fnlDataTMP);
CollectionUtils.isEqualCollection(joinedFnlData, joinedFnlDataTMP);
Things to note:
- This is probably not the cheapest operation - so it should not be invoked too often in a time critical scenario (e.g. UI thread)
- It does not do a "real" equals - for that you would have to do a nested loop like in the above answer. This checks that both joined lists have the same elements with the same cardinality: e.g. if fnlData has 2 lists with "1" and "2" as the only elements and fnlDataTMP has 1 list with "1", "2" as the elements, this would mark both as equal. Depending on your scenario this might be irrelevant - if this is relevant I don't see a way around nested loops.
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
if (k == unmatchingPositions.get(k)) {
This is saying if the value stored in position k of the unmatched list == k then replace it. That makes no sense. You know it's not matched so just replace it. No need for an if
You could do it all in one pass:
int listASz = listA.size();
for(int i = 0; i < listASz; i++)
{
if (listA[i] != listB[i])
{
listB[i] = /*something*/
You need to extend this a bit to handle cases where the lists aren't the same size
You don't need two lists and redundant nested loop, instead identify the indices of elements that don't match and store them into a list.
And then iterate of this list of indices and replace each corresponding element in the listB using method List.set().
List<String> listA = // initializing the list
List<String> listB = // initializing the list
List<Integer> notMatchingPositions = new ArrayList<>();
for (int i = 0; i < listA.size() && i < listB.size(); i++) {
if (!listA.get(i).equals(listB.get(i))) notMatchingPositions.add(i);
}
for (int i : notMatchingPositions) {
String newValue = someListOfValues.get(rand.nextInt(someListOfValues.size()));
listB.set(i, newValue);
}
You don't need to compare
List<Integer> c = new ArrayList<>(a);
c.removeAll(b);
And if you don't mind loosing the original list data
a.removeAll(b);
Something like this should suffice:
Set<Integer> container = new HashSet<>(ListB);
ListA.stream()
.filter(id -> !container.contains(id))
.forEach(System.out::println);
or non-stream:
Set<Integer> container = new HashSet<>(ListB);
for(Integer id : ListA)
if(!container.contains(id));
System.out.println(id);