Быстрый способ удаления дубликатов с одинаковым содержимым (custom .equals ()) из списка - PullRequest
0 голосов
/ 21 февраля 2020

Так что я искал эту «проблему» и только натолкнулся на вопросы, спрашивающие, как удалить реальные дубликаты из списка. Но я хочу удалить каждый объект, равный другому объекту в списке, в соответствии с пользовательским методом .equals ().

Здесь у меня есть пример класса с equals () переопределяемый метод:

    private static class Test {

        int x;
        float[] data;

        public Test(int x, float[] data) {
            this.x = x;
            this.data = data;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Test) {
                Test compare = (Test) obj;
                if (
                        compare.x == this.x &&
                        Arrays.equals(compare.data, this.data)
                ) {
                    return true;
                }
            }
            return false;
        }

    }

Теперь, конечно, следующее не будет тем же (без дубликатов, которые могут быть удалены, например, с помощью HashMap):

    Test test1 = new Test(3, new float[]{0.1f, 0.4f});
    Test test2 = new Test(3, new float[]{0.1f, 0.4f});

Но в моем случае они дубликаты, и я хочу оставить только один из них.

Я пришел с таким подходом:

    Test test1 = new Test(3, new float[]{0.1f, 0.4f});
    Test test2 = new Test(3, new float[]{0.1f, 0.4f});
    Test test3 = new Test(2, new float[]{0.1f, 0.5f});

    List<Test> list = new ArrayList<>();
    list.add(test1);
    list.add(test2);
    list.add(test3);

    Set<Test> noDuplicates = new HashSet<>();

    for (Test testLoop : list) {

        boolean alreadyIn = false;

        for (Test testCheck : noDuplicates) {
            if (testLoop.equals(testCheck)) {
                alreadyIn = true;
                break;
            }
        }

        if (!alreadyIn) {
            noDuplicates.add(testLoop);
        }

    }

И это прекрасно работает, но не так хорошо с точки зрения производительности. (В моем случае это важно, потому что размер списка может быть большим)

Теперь мой вопрос: Есть ли более удобный подход для достижения этого?

Ответы [ 3 ]

2 голосов
/ 21 февраля 2020

Я, возможно, совершенно неправильно понял, что вам нужно, но я думаю, что вам просто нужно перезаписать hashCode () для получения того же кода ha sh в случаях, когда equals - это true.

Так что метод которые генерируют код ha sh для compare.data. Если вы сделаете это, то можете просто добавить все элементы в hastSet для удаления дубликатов.

Запомните правило: если вы перезаписываете equals, вы должны также перезаписать hashCode.

1 голос
/ 21 февраля 2020

По определению, набор не допускает дублирования.

Set<Test> noDuplicates = new HashSet<>();
noDuplicates.addAll(list);

РЕДАКТИРОВАТЬ: чтобы это работало, вы должны также определить hashCode (), а не просто equals ().

0 голосов
/ 21 февраля 2020

HashSet s использует функцию hashCode(), чтобы определить, является ли объект дубликатом.

Таким образом, вы захотите переопределить функцию hashCode() для вашего класса Test.

Это будет выглядеть следующим образом:

private static class Test {

    int x;
    float[] data;

    ...

    @Override
    public int hashCode() {
        int hash = Arrays.hashCode(data);
        hash = hash * 31 + x;
        return hash;
    }
}

Теперь, если вы добавите элементы к HashSet, который содержит Test, он правильно расшифрует дубликаты:

Test test1 = new Test(3, new float[]{0.1f, 0.4f});
Test test2 = new Test(3, new float[]{0.1f, 0.4f});
Test test3 = new Test(2, new float[]{0.1f, 0.5f});

Set<Test> noDuplicates = new HashSet<>();

noDuplicates.add(test1);
noDuplicates.add(test2);
noDuplicates.add(test3);

Сохранить помните, что вам придется обновлять функцию hashCode() в Test каждый раз, когда вы добавляете переменную-член, которую хотите включить в проверку на равенство.

Кредит переходит к Джону Скиту для метода конкатенации ha sh функций кода, который я использовал выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...