У меня есть список массивов строк, которые могут иметь повторяющиеся записи. Я хочу получить уникальный список из этих значений.
У меня есть список массивов строк с каждым массивом, имеющим два значения String.
Примеры значений массива строк:
{"error message 1", "fail"}
{"error message 2", "N/A"}
{"error message 1", "fail"} // duplicate
{"error message 2", "fail"}
Я получаю строки "error message 1" и "fail" из элементов JSON отдельно и добавляю их к объекту массива String. Теперь я хочу уникальную комбинацию этого массива. Итак, если у меня было выше 4 массивов, я хочу иметь список из трех уникальных записей.
Из поиска в Интернете я развернулся, чтобы использовать HashSet для моего варианта использования (порядок не имеет значения). Тем не менее, HashSet добавляет все 4 записи в набор. Я даже пытался использовать " contains ", чтобы проверить, существует ли объект, но это тоже не сработало. Я считаю, это потому, что метод contains сравнивает " reference ", а не " value ". Является ли это причиной того, что HashSet добавляет повторяющиеся значения?
Мой код для добавления этих массивов String в HashSet
Set<String[]> uniqueSet = new HashSet<String[]>();
if(!uniqueSet.contains(new String[] {errorMessage,result})) // I get errorMessage and result as separate Strings
uniqueSet.add(new String[] {errorMessage,result}); // I expect to have only 3 values here in the uniqueSet. But it adds all 4.
Из ответов на связанные вопросы по SO я понимаю, что хэш-код и равные методы должны быть перезаписаны, если это необходимо. Но, я не уверен, как мне это сделать в моем случае, если это то, чего я не хватает?
Кроме того, дайте мне знать, если у вас есть другие предложения, чтобы лучше хранить массивы String однозначно.
С Уважением,
Rumit
Вы можете использовать List
вместо массивов. Если вы используете списки из пакета java.util
, они должны уже реализовать hashCode()
и equals(Object)
таким образом, который соответствует вашим потребностям (глубокие равенства и глубокий hasCode):
String[][] stringArrays = new String[][] {
{"error message 1", "fail"},
{"error message 2", "N/A"},
{"error message 1", "fail"}, // duplicate
{"error message 2", "fail"}
};
Set<List<String>> uniqueSet = new HashSet<List<String>>();
for (String[] a : stringLists) {
uniqueSet.add(Arrays.asList(a));
}
// uniqueSet.size() should return 3 here
Поскольку Java не имеет кортежей, одним из способов его решения будет использование кортежа -
class Pair<L,R> {
private final L left;
private final R right;
Pair(L left, R right) {
this.left = left;
this.right = right;
}
L getLeft() {
return left;
}
R getRight() {
return right;
}
@Override
public int hashCode() { return left.hashCode() ^ right.hashCode(); }
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof Pair)) return false;
Pair pairo = (Pair) o;
return this.left.equals(pairo.getLeft()) &&
this.right.equals(pairo.getRight());
}
}
Вместо использования Set<String[]>
создайте новый класс, например:
public class MyError {
private String message;
private String detail;
//constructors, getters and setters
public boolean equals(Object other) {
//implement equals here - i suggest you to use an IDE auto generated equals()
}
}
И используйте Set<MyError>
. Итак, когда вы это сделаете:
uniqueSet.add(new MyError(errorMessage, result));
он будет подавлять дублированные записи правильно из-за реализации равных.
Я не знаю, подходит ли оно вашим потребностям, но (по крайней мере) более быстрое решение будет использовать HashMap
.
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put("error message 1","fail");
hashMap.put("error message 2","fail");
hashMap.put("error message 1","N/A");
Результатом будет только два элемента в списке, поскольку элемент Key (в этом случае "сообщение об ошибке 1") будет перезаписан следующим, который вы ввели в список.
Результат:
hashMap=[{"error message 1","N/A"},{"error message 2","fail"}];