0

I am trying to add unique elements to an array using the below code. I used Ignorecase, but still I am getting duplicates.

    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;

    public class RemoveDuplicatesIgnoreCase {

    public static void main(String args[]) {

        // String Array with duplicates Colors
        String[] colorArray={"Black","BLACK","black","Cobalt","COBALT","cobalt","IVORY","Ivory","ivory","White","WHITE","white"};
        List<String> uniqueColorList=new ArrayList<String>();
        for (String color : colorArray) {
            if(!uniqueColorList.contains(color)&& !uniqueColorList.contains(color.toLowerCase())&& !uniqueColorList.contains(color.toUpperCase()))
            {
                uniqueColorList.add(color);
            }
        }
        Iterator<String> itr=uniqueColorList.iterator();
        while(itr.hasNext())
        {
            System.out.println(itr.next());
        }

    }

}

Output:

Black
BLACK
Cobalt
COBALT
IVORY
White
WHITE

I want to avoid adding case sensitive & case insensitive duplicates.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Ramu
  • 161
  • 7

13 Answers13

4

I would use a SET instead of a ArrayList and add the string in lowercase. The Set doesn't allowed duplicate element.

Set<String> uniqueColorList = new HashSet<String>();
for (String color : colorArray) {
    uniqueColorList.add(color.toLowerCase());
}
TheEwook
  • 11,037
  • 6
  • 36
  • 55
2

you have to lowerCase both values, to find a match

deterministicFail
  • 1,271
  • 9
  • 28
1

I would use a Set of lowercase versions of the colors to track uniqueness:

public static void main(String args[]) {

    String[] colorArray={"Black","BLACK","black","Cobalt","COBALT","cobalt","IVORY","Ivory","ivory","White","WHITE","white"};

    List<String> colors = new ArrayList<String>();
    Set<String> uniqueColors = new HashSet<String>();
    for (String color : colorArray) {
        if (set.add(color.toLowerCase()) {
            uniqueColors.add(color);
        }
    }
    // colors now contains case-insensitive unique names 
}

This code makes use of two things about a Set:

  1. Sets allow only unique values, so by putting in lowercase copies of the string we get the case-insensitive part taken care of
  2. The add() method returns true if the operation changed the set, which will only happen if the value being added is new to the set, Using this return value avoids having to use contains() - simply attempt to add the value and you'll find out if it's unique or not.
Bohemian
  • 412,405
  • 93
  • 575
  • 722
1

I think the RIGHT way to do this would be encapsulating the Color in an Object. It is only minimal overhead and makes your code A LOT more readable:

public class ColorString {
    public final String str;

    public ColorString(String str) {
      this.str = str;
    }

    public boolean equals(Object obj) {
        if (obj == null) return false;
        if (obj == this) return true;
        if (!(obj instanceof ColorString )) return false;

        ColorString col = (ColorString) obj;

        if (this.str == null) return (col.str == null);

        return this.str.equalsIgnoreCase(col.str);
    }

    public int hashCode() { // Always override hashCode AND equals
        return str.toLowerCase().hashCode();
    }

}

If you do it like this, you can use all the standard-methods, you can use a Set, an ArrayList.contains and so on. This solution is more sensible, since it is the representation of the idea: You don't have Strings, but you have a "color" and you have special rules, when two "color"s should be considered equal or not.

And if you want to expand your solution e.g. by allowing multiple colors with similar names to be treated as the same "color" you just have to change one method and everything still works!

Falco
  • 3,287
  • 23
  • 26
0

Your problem is that you only cover all lower-case and all upper-case Strings, and not any other mix of cases (e.g. you also have capitalized Strings).

To make things short, you can just extend ArrayList and override contains to use ignore-case comparison for each String , as suggested in this thread:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class RemoveDuplicatesIgnoreCase {
    public static void main(String args[]) {

        // String Array with duplicates Colors
        String[] colorArray={"Black","BLACK","black","Cobalt","COBALT","cobalt","IVORY","Ivory","ivory","White","WHITE","white"};
        List<String> uniqueColorList=new IgnoreCaseStringList<String>();
        for (String color : colorArray) {
            if(!uniqueColorList.contains(color))
            {
                uniqueColorList.add(color);
            }
        }
        Iterator<String> itr=uniqueColorList.iterator();
        while(itr.hasNext())
        {
            System.out.println(itr.next());
        }

    }

}

public class IgnoreCaseStringList extends ArrayList<String> {
    @Override
    public boolean contains(Object o) {
        String paramStr = (String)o;
        for (String s : this) {
            if (paramStr.equalsIgnoreCase(s)) return true;
        }
        return false;
    }
}
Community
  • 1
  • 1
Domi
  • 22,151
  • 15
  • 92
  • 122
0

It doesn't work because you start by adding Black which is neither uppercase nor lowercase.

You could just decide to add uppercase or lowercase strings, and better yet, use a TreeSet if ordering doesn't matter to you. TreeSet will make it sorted alphabeticly.

Esben Skov Pedersen
  • 4,437
  • 2
  • 32
  • 46
0
I want to avoid adding case sensitive & case insensitive duplicates.

You have to get all Strings in to either lowercase or uppercase the moment you are compare String same as comparing values.

you can use equalsIgnoreCase()

But better and easy way is use a Set since it keep unique vales only.

Set<String> uniqueVal = new HashSet<String>();
for (String color : colorArray) {
    uniqueVal.add(color.toLowerCase());
}

you can convert Set into List again

List<String> uniqueList=new ArrayList<>(uniqueVal); 
// Now list contains unique values only 
Ruchira Gayan Ranaweera
  • 34,993
  • 17
  • 75
  • 115
0

The reason is you are checikng for all lowercase

When you are checking for BLACK there is Black in the list but Black != black.

The first char of the lowercase string is uppercase.

Wald
  • 1,063
  • 7
  • 13
0

first off this part:

uniqueColorList.contains(color)

won't work, this is because when it does .equals on the strings, the case is different. then your next problem is that the lower and upper case don't work, because the first one if mixed. What it boils down to is the fact that WHITE and White are technically unique. The easiest option is to just use a single set case, as per ZouZou's suggestion. otherwise you need to do what Domi said and implement your own contains method to do a case insensitive check

M21B8
  • 1,867
  • 10
  • 20
0
Set<String> duplicateDection = new HashSet<>()
if (duplicateDection.add(color.toLowerCase())) {
  uniqueColorList.add(color);
}

If removing items from the list you also need to remove them from the duplicate detection:

uniqueColorList.remove(color);
duplicateDetection.remove(color.toLowerCase());
Tim B
  • 40,716
  • 16
  • 83
  • 128
0

You only check that list being build already contains 'same case' 'upper case' 'lower case' variants of the element to be added, so the search is not exhaustive if the list contains already a string with the different case combination then it passes condition and adds the color.

0

Try this..

public static void main(String[] a) {
    String[] colorArray = {"Black", "BLACK", "black", "Cobalt", "COBALT", "cobalt", "IVORY", "Ivory", "ivory", "White", "WHITE", "white"};
    List<String> uniqueColorList = new ArrayList<String>();

    for (int i = 0; i < colorArray.length; i++) {
        for (int j = i+1; j < colorArray.length; j++) {
            if (!colorArray[i].equals("")) {
                if (colorArray[i].equalsIgnoreCase(colorArray[j])) {
                    colorArray[j] = "";
                }
            }
        }
    }
    System.out.println(Arrays.toString(colorArray));;
    for (String color : colorArray) {
        if (!color.equals("")) {
            uniqueColorList.add(color);
        }
    }
    Iterator<String> itr = uniqueColorList.iterator();
    while (itr.hasNext()) {
        System.out.println(itr.next());
    }
}
subash
  • 3,116
  • 3
  • 18
  • 22
0
public static void main(String args[]) {

    String[] colorArray={"Black","BLACK","black","Cobalt","COBALT","cobalt","IVORY","Ivory","ivory","White","WHITE","white"};
    Set<String> uniqueColorList = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
    for (String color : colorArray) {
            uniqueColorList.add(color);
    }
    Iterator<String> itr=uniqueColorList.iterator();
    while(itr.hasNext())
    {
        System.out.println(itr.next());
    }

}

this will solve your problem

Output:

Black
Cobalt
IVORY
White
dev2d
  • 4,245
  • 3
  • 31
  • 54