Определить дубликаты в списке - PullRequest
99 голосов
/ 14 сентября 2011

У меня есть список типа Integer, например:

[1, 1, 2, 3, 3, 3]

Я хотел бы, чтобы метод возвращал все дубликаты, например:

[1, 3]

Каков наилучший способ сделать это?

Ответы [ 28 ]

166 голосов
/ 14 сентября 2011

Метод add из Set возвращает логическое значение, если значение уже существует (true, если оно не существует, false, если оно уже существует, см. Установка документации ).

Так что просто переберите все значения:

public Set<Integer> findDuplicates(List<Integer> listContainingDuplicates)
{ 
  final Set<Integer> setToReturn = new HashSet<>(); 
  final Set<Integer> set1 = new HashSet<>();

  for (Integer yourInt : listContainingDuplicates)
  {
   if (!set1.add(yourInt))
   {
    setToReturn.add(yourInt);
   }
  }
  return setToReturn;
}
42 голосов
/ 09 мая 2013

Мне тоже нужно было это решить. Я использовал решение Лейфга и сделал его общим.

private <T> Set<T> findDuplicates(Collection<T> collection) {

    Set<T> duplicates = new LinkedHashSet<>();
    Set<T> uniques = new HashSet<>();

    for(T t : collection) {
        if(!uniques.add(t)) {
            duplicates.add(t);
        }
    }

    return duplicates;
}
30 голосов
/ 26 июля 2015

Я взял решение Джона Стриклера и переделал его для использования API потоков, представленного в JDK8:

private <T> Set<T> findDuplicates(Collection<T> collection) {
    Set<T> uniques = new HashSet<>();
    return collection.stream()
        .filter(e -> !uniques.add(e))
        .collect(Collectors.toSet());
}
11 голосов
/ 14 сентября 2011
int[] nums =  new int[] {1, 1, 2, 3, 3, 3};
Arrays.sort(nums);
for (int i = 0; i < nums.length-1; i++) {

    if (nums[i] == nums[i+1]) {
        System.out.println("duplicate item "+nums[i+1]+" at Location"+(i+1) );
    }

}

Очевидно, что вы можете делать с ними все, что захотите (например, положить в набор для получения уникального списка повторяющихся значений) вместо печати ... Это также дает преимущество в записи местоположения дубликатов.

8 голосов
/ 12 сентября 2018

Базовое решение Java 8:

List duplicates =    
list.stream().collect(Collectors.groupingBy(Function.identity()))
    .entrySet()
    .stream()
    .filter(e -> e.getValue().size() > 1)
    .map(Map.Entry::getKey)
    .collect(Collectors.toList());
8 голосов
/ 16 января 2019

Вот решение с использованием Streams с Java 8

// lets assume the original list is filled with {1,1,2,3,6,3,8,7}
List<String> original = new ArrayList<>();
List<String> result = new ArrayList<>();

Вы просто смотрите, если частота этого объекта в вашем списке более одного раза. Затем вызовите .distinct (), чтобы в вашем результате были только уникальные элементы

result = original.stream()
    .filter(e -> Collections.frequency(original, e) > 1)
    .distinct()
    .collect(Collectors.toList());
// returns {1,3}
// returns only numbers which occur more than once

result = original.stream()
    .filter(e -> Collections.frequency(original, e) == 1)
    .collect(Collectors.toList());
// returns {2,6,8,7}
// returns numbers which occur only once

result = original.stream()
    .distinct()
    .collect(Collectors.toList());
// returns {1,2,3,6,8,7}
// returns the list without duplicates
7 голосов
/ 30 октября 2015

Использование Guava на Java 8

private Set<Integer> findDuplicates(List<Integer> input) {
    // Linked* preserves insertion order so the returned Sets iteration order is somewhat like the original list
    LinkedHashMultiset<Integer> duplicates = LinkedHashMultiset.create(input);

    // Remove all entries with a count of 1
    duplicates.entrySet().removeIf(entry -> entry.getCount() == 1);

    return duplicates.elementSet();
}
6 голосов
/ 14 сентября 2011

Это также работает:

public static Set<Integer> findDuplicates(List<Integer> input) {
    List<Integer> copy = new ArrayList<Integer>(input);
    for (Integer value : new HashSet<Integer>(input)) {
        copy.remove(value);
    }
    return new HashSet<Integer>(copy);
}
5 голосов
/ 14 сентября 2011

Вы можете использовать что-то вроде этого:

List<Integer> newList = new ArrayList<Integer>();
for(int i : yourOldList)
{
    yourOldList.remove(i);
    if(yourOldList.contains(i) && !newList.contains(i)) newList.add(i);
}
4 голосов
/ 14 сентября 2011

Используйте MultiMap для сохранения каждого значения в качестве набора ключ / значение. Затем переберите ключи и найдите их с несколькими значениями.

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