views:

182

answers:

8

I have two String arrays a,b.

String a [] = {"one","two","three"};
String b [] = {"one","Two","Three","four"};

I need to check whether both arrays are same or not , with case Insensitive . I know , the following piece of code is perfect for case sensitive.

List <String> l1 = Arrays.asList(a);
List <String> l2 = Arrays.asList(b);
System.out.println(l2.containsAll(l1));  

Is there any other way to compare two string array (case Insensitive ) using collection?

A: 

check it in nested loops if you want custom comparison. or if you have large sets of data it might be cheaper to sort arrays first

Andrey
+1  A: 

Couldn't you just loop it or use some sort of linq (Sorry just noticed this was java you cant use linq...?)

    List<string> matches = new List<string>();
    bool isSame=true;

    foreach(string s1 in l1)
     {
      foreach(string s2 in l2)
        {
         if(s1.ToLower() == s2.ToLower()) 
          matches.Add(s1);
         else
            {
             isSame=false;
             break;
            }
        }
       if (isSame) 
            continue;           
       else
            break;
     }

if (isSame)
    Console.Writeline("They are the same")
else
    Console.Writeline("Not the same");

You may want to check the count as I did not add that to the code, for instance l1.count > l2.count (in this case you know whether or not they are the same by the number of elements in the list). Simple test before even looping:

if (l1.Count != l2.Count) {
 //don't even bother looping
 //display no matches
}
else {
 //place rest of code here since l1.count = l2.count
}
  • CRAP DIDN'T REALIZE THIS WAS FOR JAVA THOUGHT IT WAS FOR C#. APPLY SAME LOGIC TO JAVA THOUGH...
JonH
Thanks for your quick answer, I'm expecting the answer using java collection.
Thomman
@Thomman - Ya sorry I just realized you were asking for java I thought C#. Anyhow it should be very similiar as I have heard java developers look at C# and can transition very very easily. So look at the code and see if you can convert it to fit java.
JonH
Yes jonH, I implemented using nested for loop and equalsIgnoreCase . But I need some logic using java collection.
Thomman
A: 

Your sample data are sorted. If this is guaranteed to be the case in reality, you should do as Andrey says, and use nested loops on the arrays themselves, breaking if/when you find an inequal pair of entries.

If they're not guaranteed to be sorted, I'd dump each of them into a HashSet, and then you can use java's Set containsAll method.

Edit: As Thomman pointed out, containsAll() ultimately relies on equals(). So in order to get the case-insensitive checking your question requests, you have two choices:

1) Upcase or downcase the strings on insertion into the sets. On consideration, I'm not crazy about this method, since not only will you lose duplicate entries, but you'll also fold entries differentiated by case. And so these lists would look to be equal to each other:


String a [] = {"one","one","one", "Two"};
String b [] = {"One", Two"};

2) The other choice is to put your strings into holder objects which override equals(), doing comparison in a case-insensitive way.

CPerkins
The Set containsAll method is case sensitive.
Thomman
@Thomman - Good point. I missed the "case insensitive" part of the OP's question. I've edited in response. Thanks.
CPerkins
+1  A: 

If the arrays don't contain duplicates, one way to do this in O(N) is to use a Set that represents a canonical form of the strings in the array. Something like this:

static Set<String> canonicalSet(String[] arr) {
    Set<String> upperSet = new HashSet<String>();
    for (String s : arr) {
        upperSet.add(s.toUpperCase());
    }
    return upperSet;
}
static boolean equalsCanonically(String[] arr1, String[] arr2) {
    return canonicalSet(arr1).equals(canonicalSet(arr2));
}

This is time-optimal.

You can also do variations on this technique to save more space, e.g. instead of constructing the canonical sets and comparing them, you can construct the canonical set for arr1, and then remove entries from that set according to elements of arr2. It the set is empty afterward, and you can always find what you need to remove, the two arrays are canonically equal.

static boolean equalsCanonically2(String[] arr1, String[] arr2) {
    Set<String> canon = canonicalSet(arr1);
    for (String s : arr2) {
        if (!canon.remove(s.toUpperCase())) return false;
    }
    return canon.isEmpty();
}

You can also do a simple size-comparison check if you think it's worth it (i.e. if often the two arrays don't even have the same number of elements).

If there are duplicates in the arrays, then the Set method will not work as is. You'd need a multiset, and you can either implement your own, or use Google Collections'.


There are also O(N log N) ways to do this involving sorting the strings. You can sort both arrays and then do a simple linear check. A case-insensitive comparator must be used, and in fact it's already there as String.CASE_INSENSITIVE_ORDER.

static boolean equalsCanonically3(String[] arr1, String[] arr2) {
    int N = arr1.length;
    if (arr2.length != N) return false;
    Arrays.sort(arr1, String.CASE_INSENSITIVE_ORDER);
    Arrays.sort(arr2, String.CASE_INSENSITIVE_ORDER);
    for (int i = 0; i < N; i++) {
        if (String.CASE_INSENSITIVE_ORDER.compare(arr1[i], arr2[i]) != 0) {
            return false;
        }
    }
    return true;
}

This last technique works even if the arrays contain duplicates. It does it O(N log N). It sorts the arrays passed as parameters, so if the original state is important, you want to pass their clone() instead.

polygenelubricants
Thanks, I solved this by using TreeSet with case insensitive comparator.
Thomman
That only works if the arrays don't contain duplicates.
polygenelubricants
+1  A: 

You could use a TreeMap with a case-insensitive comparator.

JRL
Thanks JRL, the correct one is TreeSet with a case-insensitive comparator.
Thomman
`TreeSet` only works when arrays don't contain duplicates. Otherwise, `["one", "one"]` would be canonically equal to `["ONE"]`. See my answer for detail.
polygenelubricants
Yes, you are correct. My inputs were unique/no duplicates, sorry could not add this in question.
Thomman
Then use `HashSet` and do it in `O(N)`.
polygenelubricants
Does HashSet support case-insensitive comparator ?
Thomman
You store the canonical form of the strings in the `HashSet`, e.g. the strings converted to uppercase. It takes more space because it creates new strings, but it's `O(N)` expected asymptotic complexity.
polygenelubricants
A: 

You could first check if their lengths are equal. Then you could put items of a in HashMap and go over b and check if the items are there.

fastcodejava
A: 

Finally , I used TreeSet with case insensitive comparator.

Example :

 String [] oldVal = {"one","two","three","Four"};
 String [] newVal = {"one","Two","Three","four"};

 Set <String> set1 = new TreeSet <String> (String.CASE_INSENSITIVE_ORDER);
 Set <String> set2 = new TreeSet <String> (String.CASE_INSENSITIVE_ORDER);

 set1.addAll(Arrays.asList(oldVal));
 set2.addAll(Arrays.asList(newVal));

 System.out.println("--Using Tree Set --- "+ set1.containsAll(set2));  // Return True

Thanks Guys..

Thomman
It also prints true when `String [] oldVal = {"one","one","two"}; String [] newVal = {"ONE"};`. THIS IS NOT THE SOLUTION!
polygenelubricants
This is the solution if the inputs are unique/no duplicate.
Thomman
No, it also prints true when `String [] oldVal = {"one","two"}; String [] newVal = {"ONE"};`. `containsAll` needs to be checked both ways.
polygenelubricants
I forgot to explain the full logic, my requirement is compare two string arrays, and return false if two arrays are not equal. please see the following algorithmStep 1 : Null checkStep 2 : Check arrays size, if both are different , then return false (two arrays are different)Step 3 : If both arrays are same size , then check for contents (need case insensitive)
Thomman
A: 

Using one for loop -

String [] oldVal = {"one","two","three","Four"};
String [] newVal = {"one","Two","Three","four"};


if(oldVal.length == newVal.length)
{
 //
 for(int y =0; y<oldVal.length; y++)
 {
  oldVal[y] = oldVal[y].toUpperCase();
  newVal[y] = newVal[y].toUpperCase();
 }

 return Arrays.asList(oldVal).containsAll(Arrays.asList(newVal));

}
 return false;  
Thomman