Ответ 1
Вы не можете. массивы используют стандартную реализацию Object.hashCode() по умолчанию, и вы не можете ее переопределить. Не используйте Arrays в качестве ключей в HashMap/HashSet!
Вместо этого используйте набор списков.
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. Или, если на то пошло, общий массив? Есть ли лучший способ выполнить то, что я пытаюсь сделать?
Вы не можете. массивы используют стандартную реализацию Object.hashCode() по умолчанию, и вы не можете ее переопределить. Не используйте Arrays в качестве ключей в HashMap/HashSet!
Вместо этого используйте набор списков.
"Лучший способ" - использовать коллекции. Используйте 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);
}
}
hashCode()
массивов использует реализацию по умолчанию, которая не учитывает элементы, и вы не можете изменить это.
Вместо этого вы можете использовать List
, с hashCode()
, вычисленным на основе хэш-кодов его элементов. ArrayList
(как и большинство реализаций) использует такую функцию.
Альтернативно (но менее предпочтительно, если вы не вынуждены каким-то образом использовать массивы), вы можете использовать "специальный" HashSet
, вместо вызова key.hashCode()
invoke Arrays.hashCode(array)
. Чтобы реализовать это расширение HashMap
, а затем используйте Collections.newSetFromMap(map)
Фактически вы используете метод 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>();
Собственно, вы можете. Вы можете использовать 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;
});
Под капотом это будет выглядеть как алфавитное сортированное дерево.