Storing arrays in Set and avoiding duplicates

前端 未结 5 1751
你的背包
你的背包 2020-12-24 06:09
HashSet boog = new HashSet();
boog.add(new String[]{\"a\", \"b\", \"c\"});
boog.add(new String[]{\"a\", \"b\", \"c\"});
boog.add(new          


        
相关标签:
5条回答
  • 2020-12-24 06:29

    The "better way" is to use collections. Use a List instead of a String[]:

    Set<List<String>> boog = //...
    boog.add(Arrays.asList("a", "b", "c"));
    boog.add(Arrays.asList("a", "b", "c"));
    boog.add(Arrays.asList("a", "b", "d"));
    
    System.out.println(boog.size()); // 2
    

    Edit

    If you absolutely needed to use arrays as keys, you could build a transparent wrapper around each key and put that in the map. Some libraries help you with that. For example, here's how you could do a Set<String[]> using Trove:

    Set<String[]> boog = new TCustomHashSet<String[]>(new ArrayHashingStrategy());
    
    boog.add(new String[]{"a", "b", "c"});
    boog.add(new String[]{"a", "b", "c"});
    boog.add(new String[]{"a", "b", "d"});
    
    System.out.println(boog.size()); // 2
    
    //...
    public class ArrayHashingStrategy extends HashingStrategy<Object[]> {
    
       public int computeHashCode(Object[] array) {
          return Arrays.hashCode(array);
       }
    
       public boolean equals(Object[] arr1, Object[] arr2) {
          return Arrays.equals(arr1, arr2);
       }
    }        
    
    0 讨论(0)
  • 2020-12-24 06:38

    You can't. arrays use the default identity-based Object.hashCode() implementation and there's no way you can override that. Don't use Arrays as keys in a HashMap / HashSet!

    Use a Set of Lists instead.

    0 讨论(0)
  • 2020-12-24 06:38

    Actually, you can. You can use TreeSet with provided Comparator. In your case it will be something like:

    Set<String[]> boog = new TreeSet<>((o1, o2) -> {
        for (int i = 0; i < o1.length; i++){
            int cmp = o1[i].compareTo(o2[i]);
            if (cmp != 0) {
                return cmp;
            }
        }
        return o1.length - o2.length;
    });
    

    Under the hood it will looks like alphabetic sorted tree.

    0 讨论(0)
  • 2020-12-24 06:50

    You are actually using the default hashCode method returning different values for all your different arrays!

    The best way to solve this is either to use a Collection (such as a List or a Set) or to define your own wrapper class such as:

    public class StringArray {
        public String[] stringArray;
    
        [...] // constructors and methods
    
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            for(String string : stringArray){
                result = prime * result + ((string == null) ? 0 : string.hashCode());
            }
        }
    }
    

    This class actually uses pretty much the same hashCode method as the one for the List.

    You now handle:

    HashSet<StringArray> boog = new HashSet<StringArray>();
    
    0 讨论(0)
  • 2020-12-24 06:51

    hashCode() of arrays uses the default implementation, which doesn't take into account the elements, and you can't change that.

    You can use a List instead, with a hashCode() calculated based on the hashcodes of its elements. ArrayList (as most implementations) uses such function.


    Alternatively (but less preferable, unless you are forced somehow to use arrays), you can use a 'special' HashSet where instead of invoking key.hashCode() invoke Arrays.hashCode(array). To implement that extend HashMap and then use Collections.newSetFromMap(map)

    0 讨论(0)
提交回复
热议问题