При ежедневном развитии бизнеса иногда возникают сценарии, когда необходимо удалить повторяющиеся данные в коллекции 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);
}
}
Результат выполнения вышеуказанной программы следующий:Преимущества этого метода: он относительно прост для понимания, а конечная коллекция также упорядочена. Упорядочивание здесь означает, что порядок новой коллекции такой же, как порядок исходной коллекции, но недостатком является то, что код реализации немного больше, недостаточно лаконичен и элегантен.
Способ 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);
}
}
Результат выполнения вышеуказанной программы следующий:Реализация этого метода меньше, чем у предыдущего метода, и не требует новой коллекции, но новая коллекция, полученная этим методом, является неупорядоченной, то есть порядок расположения новой коллекции несовместим с исходной коллекцией, так что это не самое отличное решение.
Способ 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);
}
}
Результат выполнения вышеуказанной программы следующий:Код реализации этого метода относительно прост, но недостатком является то, что 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);
}
}
Результат выполнения вышеуказанной программы следующий:Из приведенного выше кода и результатов выполнения видно, что 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);
}
}
Результат выполнения вышеуказанной программы следующий:К сожалению, хотя 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);
}
}
Результат выполнения вышеуказанной программы следующий:Отличие реализации дедупликации Stream от других методов в том, что ему не нужно создавать новую коллекцию, достаточно использовать себя для получения результата дедупликации, при этом код реализации также очень прост, и порядок коллекции после дедупликации тоже такой же, как порядок исходной коллекции.Последовательность является нашим главным приоритетом для дедупликации.
Суммировать
В этой статье мы представляем 6 методов дедупликации наборов.Среди них реализация является наиболее лаконичной, а порядок после дедупликации может соответствовать исходному набору.Существует всего два метода: дедупликация LinkedHashSet и дедупликация Stream, и последние методы дедупликации, которые не требуют использования новых коллекций, являются нашим предпочтительным методом дедупликации.
Самостоятельно судить о правильном и неправильном, слушать других и подсчитывать выгоды и потери.
Введение в блоггер: программисты после 80-х, «настойчивые» в ведении блога в течение 11 лет, хобби: чтение, бег трусцой, бадминтон.
Мой официальный аккаунт: Анализ вопросов Java-интервью
Личный WeChat: GG_Stone, добро пожаловать в круг друзей, просто поставьте лайк.