Подтвердить что ты не робот

Хранение массивов в наборе и исключение дубликатов

HashSet<String[]> boog = new HashSet<String[]>();
boog.add(new String[]{"a", "b", "c"});
boog.add(new String[]{"a", "b", "c"});
boog.add(new String[]{"a", "b", "d"});

приводит к

[a, b, c]
[a, b, d]
[a, b, c]

где [a,b,c] повторяется, поэтому функция хэша не работает должным образом. Как я могу поменять метод Hash для массивов String. Или, если на то пошло, общий массив? Есть ли лучший способ выполнить то, что я пытаюсь сделать?

4b9b3361

Ответ 1

Вы не можете. массивы используют стандартную реализацию Object.hashCode() по умолчанию, и вы не можете ее переопределить. Не используйте Arrays в качестве ключей в HashMap/HashSet!

Вместо этого используйте набор списков.

Ответ 2

"Лучший способ" - использовать коллекции. Используйте List вместо 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

Изменить

Если вам абсолютно необходимо использовать массивы в качестве ключей, вы можете создать прозрачную оболочку вокруг каждого ключа и поместить ее на карту. Некоторые библиотеки помогают вам в этом. Например, здесь вы можете сделать Set<String[]> с помощью 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);
   }
}        

Ответ 3

hashCode() массивов использует реализацию по умолчанию, которая не учитывает элементы, и вы не можете изменить это.

Вместо этого вы можете использовать List, с hashCode(), вычисленным на основе хэш-кодов его элементов. ArrayList (как и большинство реализаций) использует такую ​​функцию.


Альтернативно (но менее предпочтительно, если вы не вынуждены каким-то образом использовать массивы), вы можете использовать "специальный" HashSet, вместо вызова key.hashCode() invoke Arrays.hashCode(array). Чтобы реализовать это расширение HashMap, а затем используйте Collections.newSetFromMap(map)

Ответ 4

Фактически вы используете метод hashCode по умолчанию, возвращающий разные значения для всех ваших разных массивов!

Лучший способ решить это либо использовать Collection (например, List, либо Set), либо определить свой собственный класс-оболочку, например:

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());
        }
    }
}

Этот класс фактически использует почти тот же метод hashCode, что и для List.

Теперь вы обрабатываете:

HashSet<StringArray> boog = new HashSet<StringArray>();

Ответ 5

Собственно, вы можете. Вы можете использовать TreeSet с предоставленным Comparator. В вашем случае это будет что-то вроде:

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;
});

Под капотом это будет выглядеть как алфавитное сортированное дерево.