Перечислите 6 способов удаления дубликатов, этот способ самый совершенный!

Java задняя часть
Перечислите 6 способов удаления дубликатов, этот способ самый совершенный!

При ежедневном развитии бизнеса иногда возникают сценарии, когда необходимо удалить повторяющиеся данные в коллекции List. В настоящее время некоторые учащиеся могут спросить: почему бы не использовать Set или LinkedHashSet напрямую? Не будет ли проблем с дублированием данных? ​

Должен сказать, что одноклассники, которые могут задать этот вопрос, очень остроумны и с первого взгляда видят суть проблемы. ​

Однако ситуация, возникающая при реальном развитии бизнеса, будет более сложной. Например, коллекция List может быть проблемой, оставшейся от истории, или это может быть связано с ограничением типа, возвращаемым вызывающим интерфейсом, который может получить только List, или код написан наполовину, а проблема обнаружена при объединении нескольких коллекций Причин этой проблемы много, поэтому я не буду перечислять их все здесь. ​

После обнаружения этой проблемы, если вы можете изменить исходный код и заменить исходный тип списка типом набора, вы можете напрямую изменить тип набора. Но если вы вообще не можете его модифицировать, или стоимость модификации слишком высока, то следующие 6 методов дедупликации помогут вам решить проблему.

Предварительное знание

Перед официальным стартом давайте разберемся с двумя наборами понятий:Неупорядоченные и упорядоченные наборы и неупорядоченные и упорядоченные. Поскольку эти две группы понятий будут неоднократно упоминаться в следующей реализации метода, необходимо уточнить их перед официальным стартом.

неупорядоченная коллекция

Неупорядоченный набор означает, что порядок чтения данных и порядок вставки данных несовместимы. Например, порядок вставки коллекции: 1, 5, 3, 7, а коллекция коллекции: 1, 3, 5, 7.

отсортированный набор

Концепция упорядоченного набора противоположна концепции неупорядоченного набора, что означает, что порядок чтения набора согласуется с порядком вставки. Например, порядок вставки данных: 1, 5, 3, 7, тогда и порядок чтения: 1, 5, 3, 7.

порядок и беспорядок

Из приведенных выше неупорядоченных множеств и упорядоченных множеств можно вывести понятия упорядоченного и неупорядоченного. Упорядоченный относится к порядку, в котором данные упорядочиваются и считываются в соответствии с нашими ожиданиями, который называется упорядоченным. Беспорядок означает, что порядок расположения и порядок чтения данных не соответствуют нашим ожиданиям, что называется беспорядком.

PS: Неважно, если понятия порядка и беспорядка не очень ясны, на следующих примерах мы можем лучше понять их значение.

Метод 1: содержит решение об удалении дубликатов (заказано)

Чтобы дедуплицировать данные, мы сначала думаем о создании нового набора, затем перебираем исходный набор и оцениваем элементы цикла в исходном наборе каждый раз через цикл.Если данные текущего цикла не существуют в новом наборе, вставьте их. , он уже существует Просто отбросьте его, поэтому при выполнении цикла мы получим коллекцию без повторяющихся элементов Код реализации выглядит следующим образом:

public class ListDistinctExample {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>() {{
            add(1);
            add(3);
            add(5);
            add(2);
            add(1);
            add(3);
            add(7);
            add(2);
        }};
        System.out.println("原集合:" + list);
        method(list);
    }

    /**
     * 自定义去重
     * @param list
     */
    public static void method(List<Integer> list) {
        // 新集合
        List<Integer> newList = new ArrayList<>(list.size());
        list.forEach(i -> {
            if (!newList.contains(i)) { // 如果新集合中不存在则插入
                newList.add(i);
            }
        });
        System.out.println("去重集合:" + newList);
    }
}

Результат выполнения вышеуказанной программы следующий:image.pngПреимущества этого метода: он относительно прост для понимания, а конечная коллекция также упорядочена. Упорядочивание здесь означает, что порядок новой коллекции такой же, как порядок исходной коллекции, но недостатком является то, что код реализации немного больше, недостаточно лаконичен и элегантен.

Способ 2: дедупликация итератора (неупорядоченная)

Чтобы настроить дедупликацию списка, в дополнение к новой коллекции выше, мы также можем использовать цикл итератора для оценки каждого элемента данных.Если в коллекции есть две или более копий данных текущего цикла, текущий элемент будет удален. После завершения цикла также может быть получена коллекция без повторяющихся данных Код реализации выглядит следующим образом:

public class ListDistinctExample {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>() {{
            add(1);
            add(3);
            add(5);
            add(2);
            add(1);
            add(3);
            add(7);
            add(2);
        }};
        System.out.println("原集合:" + list);
        method_1(list);
    }

    /**
     * 使用迭代器去重
     * @param list
     */
    public static void method_1(List<Integer> list) {
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            // 获取循环的值
            Integer item = iterator.next();
            // 如果存在两个相同的值
            if (list.indexOf(item) != list.lastIndexOf(item)) {
                // 移除最后那个相同的值
                iterator.remove();
            }
        }
        System.out.println("去重集合:" + list);
    }
}

Результат выполнения вышеуказанной программы следующий:image.pngРеализация этого метода меньше, чем у предыдущего метода, и не требует новой коллекции, но новая коллекция, полученная этим методом, является неупорядоченной, то есть порядок расположения новой коллекции несовместим с исходной коллекцией, так что это не самое отличное решение.

Способ 3: дедупликация HashSet (неупорядоченная)

Мы знаем, что HashSet по своей природе способен к «дедупликации», поэтому нам нужно только преобразовать коллекцию List в коллекцию HashSet.Код реализации выглядит следующим образом:

public class ListDistinctExample {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>() {{
            add(1);
            add(3);
            add(5);
            add(2);
            add(1);
            add(3);
            add(7);
            add(2);
        }};
        System.out.println("原集合:" + list);
        method_2(list);
    }

    /**
     * 使用 HashSet 去重
     * @param list
     */
    public static void method_2(List<Integer> list) {
        HashSet<Integer> set = new HashSet<>(list);
        System.out.println("去重集合:" + set);
    }
}

Результат выполнения вышеуказанной программы следующий:image.pngКод реализации этого метода относительно прост, но недостатком является то, что HashSet будет автоматически сортироваться, поэтому сортировка данных нового набора несовместима с исходным набором.Если есть требование к порядку набора, этот способ не соответствует современным требованиям.

Способ 4: дедупликация LinkedHashSet (заказная)

Так как HashSet будет автоматически сортировать и не может соответствовать требованиям, используйте LinkedHashSet, который может не только удалить дублирование, но и обеспечить порядок коллекции.Код реализации выглядит следующим образом:

public class ListDistinctExample {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>() {{
            add(1);
            add(3);
            add(5);
            add(2);
            add(1);
            add(3);
            add(7);
            add(2);
        }};
        System.out.println("原集合:" + list);
        method_3(list);
    }

    /**
     * 使用 LinkedHashSet 去重
     * @param list
     */
    public static void method_3(List<Integer> list) {
        LinkedHashSet<Integer> set = new LinkedHashSet<>(list);
        System.out.println("去重集合:" + set);
    }
}

Результат выполнения вышеуказанной программы следующий:image.pngИз приведенного выше кода и результатов выполнения видно, что LinkedHashSet пока является относительно простым методом реализации, а окончательный сгенерированный новый набор находится в том же порядке, что и исходный набор.Это метод дедупликации, который мы можем использовать.

Способ 5: дедупликация TreeSet (неупорядоченная)

В дополнение к вышеупомянутой коллекции Set мы также можем использовать коллекцию TreeSet для реализации функции дедупликации Код реализации выглядит следующим образом:

public class ListDistinctExample {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>() {{
            add(1);
            add(3);
            add(5);
            add(2);
            add(1);
            add(3);
            add(7);
            add(2);
        }};
        System.out.println("原集合:" + list);
        method_4(list);
    }

    /**
     * 使用 TreeSet 去重(无序)
     * @param list
     */
    public static void method_4(List<Integer> list) {
        TreeSet<Integer> set = new TreeSet<>(list);
        System.out.println("去重集合:" + set);
    }
}

Результат выполнения вышеуказанной программы следующий:image.pngК сожалению, хотя TreeSet относительно прост в реализации, у него та же проблема, что и у HashSet, и он будет автоматически сортироваться, поэтому он не может удовлетворить наши потребности.

Способ 6: дедупликация потока (упорядоченный)

JDK 8 предоставляет нам очень практичный метод Stream, который можно использовать для реализации многих функций, таких как следующие функции дедупликации:

public class ListDistinctExample {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>() {{
            add(1);
            add(3);
            add(5);
            add(2);
            add(1);
            add(3);
            add(7);
            add(2);
        }};
        System.out.println("原集合:" + list);
        method_5(list);
    }

    /**
     * 使用 Stream 去重
     * @param list
     */
    public static void method_5(List<Integer> list) {
        list = list.stream().distinct().collect(Collectors.toList());
        System.out.println("去重集合:" + list);
    }
}

Результат выполнения вышеуказанной программы следующий:image.pngОтличие реализации дедупликации Stream от других методов в том, что ему не нужно создавать новую коллекцию, достаточно использовать себя для получения результата дедупликации, при этом код реализации также очень прост, и порядок коллекции после дедупликации тоже такой же, как порядок исходной коллекции.Последовательность является нашим главным приоритетом для дедупликации.

Суммировать

В этой статье мы представляем 6 методов дедупликации наборов.Среди них реализация является наиболее лаконичной, а порядок после дедупликации может соответствовать исходному набору.Существует всего два метода: дедупликация LinkedHashSet и дедупликация Stream, и последние методы дедупликации, которые не требуют использования новых коллекций, являются нашим предпочтительным методом дедупликации.

Самостоятельно судить о правильном и неправильном, слушать других и подсчитывать выгоды и потери.

Введение в блоггер: программисты после 80-х, «настойчивые» в ведении блога в течение 11 лет, хобби: чтение, бег трусцой, бадминтон.

Мой официальный аккаунт: Анализ вопросов Java-интервью

Личный WeChat: GG_Stone, добро пожаловать в круг друзей, просто поставьте лайк.