Выявить дубликаты в списке


120

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

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

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

[1, 3]

Как лучше всего это сделать?


2
Гарантируется ли сортировка входного списка (как в вашем примере)?
NPE

7
отсортируйте список, затем пройдитесь по нему, сохраняя текущее и предыдущее значения. если current == ранее, у вас есть дубликат.
mcfinnigan

Нет, список не обязательно отсортирован.
самые свежие

Ответы:


183

Способ addпо Setвозвращает логическое значение , существует ли уже значение (правда , если она не существует, ложь , если она уже существует, см комплект документации ).

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

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;
}

1
Почему у вас установлен setToReturn? Разве нельзя просто использовать set1.add (yourInt) и вернуть set1?
Фил

3
Да, точно. Но когда элемент присутствует в указанном списке только один раз, элемент также добавляется. Посмотрите на пример в вопросе: Мое решение вернет [1,3], поскольку число 2 вставлено в set1, но не в setToReturn. Ваше решение вернет [1,2,3] (что не является обязательным)
leifg

1
Я предлагаю вам использовать for (Integer yourInt, чтобы избежать ненужной упаковки и распаковки, тем более что ваш ввод уже содержит Integers.
Хосам Али,

1
@JonasThelemann: вся идея набора состоит в том, что он НЕ может содержать дубликатов. следовательно: независимо от того, как часто вы добавляете 3, это всегда будет только один раз.
leifg 08

1
Кстати, в случае, если HashSetвы также должны учитывать коэффициент загрузки, например, когда вы указываете начальную емкость 100, поскольку вы хотите добавить это количество элементов, оно округляется до следующей степени 2 ( 128), что означает, что с коэффициентом загрузки по умолчанию 0.75fбудет установлен порог изменения размера 96, поэтому изменение размера будет выполняться до того, как вы добавите 100элементы. К счастью, изменение размера теперь не так дорого. В современных JRE изменение размера больше не является перехэшированием, элементы просто распределяются между двумя возможными местоположениями результатов на основе соответствующего бита.
Holger

50

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

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;
}

1
Я знаю, что это 3 года спустя, но почему LinkedHashedSet, то есть почему вам важен порядок?
Ахмад Рагаб

4
@AhmadRagab, вы правы, LinkedHashSet не требуется, если вы не заботитесь о порядке обнаружения дубликатов (что, я думаю, я сделал в то время)
Джон Стриклер,

Спасибо за продолжение!
Ахмад Рагаб

Если у вас так много входных данных, что вы хотите использовать это оптимальное решение (вместо сортировки входных данных), вы также захотите предварительно выделить размер объектов HashSet (). Без предварительного выделения вы не получите время вставки O (1) при вставке в HashSet (). Это связано с тем, что размер внутреннего хеш-массива постоянно изменяется. Затем вставки усредняются примерно до времени O (log N). Это означает, что обработка всех N элементов становится O (N log N), хотя это могло быть O (N).
johnstosh

39

Я взял решение Джона Стриклера и переделал его для использования потокового 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());
}

3
это трудно читать, не так ли? Вы создаете побочный эффект при работе с потоком, что затрудняет его рассуждение. Но это просто функциональный стиль мышления. Это лаконичный и, наверное, самый короткий путь;).
froginvasion

Для больших списков вы можете заставить это выполняться параллельно в нескольких потоках?
johnstosh

@froginvasion встроенный distinct()метод также сохраняет состояние. Не могу придумать эффективную (O (n)) отдельную операцию, которая не имеет состояния.
Wilmol

18

Вот решение с использованием потоков с 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

1
Это хорошо с точки зрения читаемости, но ДЕЙСТВИТЕЛЬНО плохо для производительности. Collections::frequencyравно O (n). Чтобы определить частоту появления элемента, необходимо просмотреть всю коллекцию. И мы вызываем это один раз для каждого элемента в коллекции, из которой создаются эти фрагменты O(n^2). Вы заметите разницу в любой коллекции, состоящей из нескольких элементов. Я бы никогда не использовал это в реальном коде.
Паван,

14

базовое решение 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());

список ввода преобразуется в карту (группировка по одинаковым значениям). затем значения карты с уникальным значением «удаляются», затем отображаются с помощью ключа, затем список списка преобразуется в список
بلال المصمودي

красивое и быстрое решение, которое можно напрямую изменить на фильтрацию по конкретным получателям элемента
arberg

11
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) );
    }

}

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


7

Использование 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();
}

7

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

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);
}

Это работает, но довольно медленно, поскольку вызов remove () в списке массивов представляет собой линейный поиск.
johnstosh

правда. Обратите внимание, что если ваш ввод содержит много дубликатов, снижение производительности будет меньше, чем если бы их было всего несколько.
Адриан Костер

6

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

List<Integer> newList = new ArrayList<Integer>();
for(int i : yourOldList)
{
    yourOldList.remove(i);
    if(yourOldList.contains(i) && !newList.contains(i)) newList.add(i);
}

2
Использование List здесь очень неэффективно
Александр Фарбер

2
И не заставляйте меня начинать использовать здесь intкак тип переменной. Это означает, что для каждой итерации Integer распаковывается один раз, а int - четыре раза!
Шон Патрик Флойд

1
Я думаю, вы можете легко получить ConcurrentModificationException при попытке удалить элемент из списка во время итерации по нему
Джад Б.

1
это 100% ConcurrentModificationException, поскольку вы просматриваете список и удаляете элементы на лету.
theo231022

5

Ламбасы могут быть решением

Integer[] nums =  new Integer[] {1, 1, 2, 3, 3, 3};
List<Integer> list = Arrays.asList(nums);

List<Integer> dps = list.stream().distinct().filter(entry -> Collections.frequency(list, entry) > 1).collect(Collectors.toList());

1
Работает, но запускает Collections.frequency для каждой записи и поэтому работает медленно.
arberg 05

4

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


3

Если вы используете Коллекции Eclipse , это будет работать:

MutableList<Integer> list = Lists.mutable.with(1, 1, 2, 3, 3, 3);
Set<Integer> dupes = list.toBag().selectByOccurrences(i -> i > 1).toSet();
Assert.assertEquals(Sets.mutable.with(1, 3), dupes);

Обновление: начиная с Eclipse Collections 9.2, теперь вы можете использоватьselectDuplicates

MutableList<Integer> list = Lists.mutable.with(1, 1, 2, 3, 3, 3);
Set<Integer> dupes = list.toBag().selectDuplicates().toSet();
Assert.assertEquals(Sets.mutable.with(1, 3), dupes);

Для этого вы также можете использовать примитивные коллекции:

IntList list = IntLists.mutable.with(1, 1, 2, 3, 3, 3);
IntSet dupes = list.toBag().selectDuplicates().toSet();
Assert.assertEquals(IntSets.mutable.with(1, 3), dupes);

Примечание: я являюсь приверженцем коллекций Eclipse.


2
public class practicese {
       public static void main(String[] args) {   

           List<Integer> listOf = new ArrayList<Integer>();
           listOf.add(3);
           listOf.add(1);
           listOf.add(2);
           listOf.add(3);
           listOf.add(3);
           listOf.add(2);
           listOf.add(1);

           List<Integer> tempList = new ArrayList<Integer>();
           for(Integer obj:listOf){
                if(!tempList.contains(obj)){
                    tempList.add(obj);

                }
            }
            System.out.println(tempList);

    }

}

Мне нравится этот ответ, просто нужно добавить еще, чтобы сохранить дубликат в другом списке. спасибо
Тьяго Мачадо

2

Подобно некоторым ответам здесь, но если вы хотите найти дубликаты на основе некоторого свойства:

  public static <T, R> Set<R> findDuplicates(Collection<? extends T> collection, Function<? super T, ? extends R> mapper) {
    Set<R> uniques = new HashSet<>();
    return collection.stream()
        .map(mapper)
        .filter(e -> !uniques.add(e))
        .collect(toSet());
  }

1

создать Map<Integer,Integer>, выполнить итерацию списка, если элемент находится на карте, увеличить его значение, в противном случае добавить его на карту с ключом = 1
, выполнить итерацию карты и добавить в списки все элементы с ключом> = 2

public static void main(String[] args) {
        List<Integer> list = new LinkedList<Integer>();
        list.add(1);
        list.add(1);
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(3);
        Map<Integer,Integer> map = new HashMap<Integer, Integer>();
        for (Integer x : list) { 
            Integer val = map.get(x);
            if (val == null) { 
                map.put(x,1);
            } else {
                map.remove(x);
                map.put(x,val+1);
            }
        }
        List<Integer> result = new LinkedList<Integer>();
        for (Entry<Integer, Integer> entry : map.entrySet()) {
            if (entry.getValue() > 1) {
                result.add(entry.getKey());
            }
        }
        for (Integer x : result) { 
            System.out.println(x);
        }

    }

Это очень хорошо. Это лучшее решение, если вам нужно знать, сколько было дубликатов. Некоторые примечания: (1) вам не нужно вызывать remove () перед выполнением put (). (2) Вы можете настроить LinkedList из массива, а не использовать повторяющиеся вызовы add (). (3) Когда val! = Null, вы можете сразу добавить x к результату. Результатом может быть набор или список, в зависимости от того, хотите ли вы вести подсчет количества дубликатов.
Джонстош

1

Компактная обобщенная версия верхнего ответа, также добавлена ​​пустая проверка и предварительно выделенный размер набора:

public static final <T> Set<T> findDuplicates(final List<T> listWhichMayHaveDuplicates) {
    final Set<T> duplicates = new HashSet<>();
    final int listSize = listWhichMayHaveDuplicates.size();
    if (listSize > 0) {
      final Set<T> tempSet = new HashSet<>(listSize);
      for (final T element : listWhichMayHaveDuplicates) {
        if (!tempSet.add(element)) {
          duplicates.add(element);
        }
      }
    }
    return duplicates;
  }

Вам нужен нулевой чек? Будет ли новый HashSet <> (0) возвращать разумный пустой набор?
johnstosh

@johnstosh этот код может быть упрощен, но проверка на ноль позволяет только инициализировать tempSetс , listSizeкогда это необходимо. Это небольшая оптимизация, но она мне нравится.
Christophe

1

Я взял ответ Себастьяна и добавил к нему keyExtractor -

    private <U, T> Set<T> findDuplicates(Collection<T> collection, Function<? super T,? extends U> keyExtractor) {
        Map<U, T> uniques = new HashMap<>(); // maps unique keys to corresponding values
        return collection.stream()
            .filter(e -> uniques.put(keyExtractor.apply(e), e) != null)
            .collect(Collectors.toSet());
    }

1

Поточно-ориентированная альтернатива такова:

/**
 * Returns all duplicates that are in the list as a new {@link Set} thread-safe.
 * <p>
 * Usually the Set will contain only the last duplicate, however the decision
 * what elements are equal depends on the implementation of the {@link List}. An
 * exotic implementation of {@link List} might decide two elements are "equal",
 * in this case multiple duplicates might be returned.
 * 
 * @param <X>  The type of element to compare.
 * @param list The list that contains the elements, never <code>null</code>.
 * @return A set of all duplicates in the list. Returns only the last duplicate.
 */
public <X extends Object> Set<X> findDuplicates(List<X> list) {
    Set<X> dups = new LinkedHashSet<>(list.size());
    synchronized (list) {
        for (X x : list) {
            if (list.indexOf(x) != list.lastIndexOf(x)) {
                dups.add(x);
            }
        }
    }
    return dups;
}

0

Попробуйте это, чтобы найти повторяющиеся элементы в списке:

ArrayList<String> arrayList1 = new ArrayList<String>(); 

arrayList1.add("A"); 
arrayList1.add("A"); 
arrayList1.add("B"); 
arrayList1.add("B"); 
arrayList1.add("B"); 
arrayList1.add("C"); 

for (int x=0; x< arrayList1.size(); x++) 
{ 
System.out.println("arrayList1 :"+arrayList1.get(x)); 
} 
Set s=new TreeSet(); 
s.addAll(arrayList1); 
Iterator it=s.iterator(); 
while (it.hasNext()) 
{ 
System.out.println("Set :"+(String)it.next()); 
} 

Да, это находит набор, но не находит список или набор тех элементов, которые являются дубликатами.
johnstosh

0

Это должно работать для отсортированных и несортированных.

public void testFindDuplicates() {

    List<Integer> list = new ArrayList<Integer>();
    list.add(1);
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(3);
    list.add(3);

    Set<Integer> result = new HashSet<Integer>();
    int currentIndex = 0;
    for (Integer i : list) {
        if (!result.contains(i) && list.subList(currentIndex + 1, list.size()).contains(i)) {
            result.add(i);
        }
        currentIndex++;
    }
    assertEquals(2, result.size());
    assertTrue(result.contains(1));
    assertTrue(result.contains(3));
}

Вызов contains () в подсписке ArrayList стоит дорого, потому что это линейный поиск. Так что это нормально для 10 предметов, но не для 10 миллионов.
johnstosh

0

Это проблема, в которой сияют функциональные техники. Например, следующее решение F # является более ясным и менее подверженным ошибкам, чем лучшее императивное решение Java (и я ежедневно работаю как с Java, так и с F #).

[1;1;2;3;3;3] 
|> Seq.countBy id 
|> Seq.choose (fun (key,count) -> if count > 1 then Some(key) else None)

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

Seq.of(1,1,2,3,3,3)
.groupBy(new Func1<Integer,Integer>() {
    public Integer call(Integer key) {
        return key;
    }
}).filter(new Predicate<Grouping<Integer,Integer>>() {
   public Boolean call(Grouping<Integer, Integer> grouping) {
        return grouping.getGrouping().count() > 1;
   }
}).map(new Func1<Grouping<Integer,Integer>,Integer>() {
    public Integer call(Grouping<Integer, Integer> grouping) {
        return grouping.getKey();
    }
});

И тогда вы видите, насколько Java по-прежнему отстой в функциональном программировании. Такая простая проблема, так сложно выразить то, что вы хотите на Java.
froginvasion

0
public class DuplicatesWithOutCollection {

    public static void main(String[] args) {

        int[] arr = new int[] { 2, 3, 4, 6, 6, 8, 10, 10, 10, 11, 12, 12 };

        boolean flag = false;
        int k = 1;
        while (k == 1) {

            arr = removeDuplicate(arr);
            flag = checkDuplicate(arr, flag);
            if (flag) {
                k = 1;
            } else {
                k = 0;
            }

        }

    }

    private static boolean checkDuplicate(int[] arr, boolean flag) {
        int i = 0;

        while (i < arr.length - 1) {

            if (arr[i] == arr[i + 1]) {

                flag = true;

            } else {
                flag = false;
            }
            i++;

        }

        return flag;
    }

    private static int[] removeDuplicate(int[] arr) {

        int i = 0, j = 0;
        int[] temp = new int[arr.length];
        while (i < arr.length - 1) {

            if (arr[i] == arr[i + 1]) {

                temp[j] = arr[i + 1];
                i = i + 2;

            } else {

                temp[j] = arr[i];
                i = i + 1;

                if (i == arr.length - 1) {
                    temp[j + 1] = arr[i + 1];
                    break;
                }

            }
            j++;

        }
        System.out.println();
        return temp;
    }

}

Реализация без использования классов Collection.Но нужно немного улучшить цикл.Помощь добровольцев заметна. Результат для приведенного выше выглядит -> 2 3 4 6 8 10 11 12
Самрат Рой

Чтобы выполнить это за меньшее количество времени, вам нужно использовать структуру данных на основе хешей для отслеживания дубликатов. Вот почему вы видите другие решения, использующие HashSet () - он встроен в Java.
johnstosh

@johnstosh Да, я знаю об этом, но я думал сделать это без использования коллекций, поэтому я упомянул в своем комментарии. Как вы видите, я прокомментировал это до февраля 2017 г. [есть методы, при которых вам вообще не нужно использовать коллекции с меньшей временной сложностью] geeksforgeeks.org/…. Я пробовал эту программу, не зная методов DS и Algo. Вам не нужно отрицать меня за это .. В любом случае спасибо.
Самрат Рой

0
import java.util.Scanner;

public class OnlyDuplicates {
    public static void main(String[] args) {
        System.out.print(" Enter a set of 10 numbers: ");
        int[] numbers = new int[10];
        Scanner input = new Scanner(System.in);
        for (int i = 0; i < numbers.length; i++) {
            numbers[i] = input.nextInt();
        }
        numbers = onlyDuplicates(numbers);
        System.out.print(" The numbers are: ");
        for (int i = 0; i < numbers.length; i++) {
            System.out.print(numbers[i] + "");
        }
    }

    public static int[] onlyDuplicates(int[] list) {
        boolean flag = true;
        int[] array = new int[0];
        array = add2Array(array, list[0]);
        for (int i = 0; i < list.length; i++) {
            for (int j = 0; j < array.length; j++) {
                if (list[i] == array[j]) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                array = add2Array(array, list[i]);
            }
            flag = true;
        }
        return array;
    }
    // Copy numbers1 to numbers2
    // If the length of numbers2 is less then numbers2, return false
    public static boolean copyArray(int[] source, int[] dest) {
        if (source.length > dest.length) {
            return false;
        }

        for (int i = 0; i < source.length; i++) {
            dest[i] = source[i];
        }
        return true;
    }
    // Increase array size by one and add integer to the end of the array
    public static int[] add2Array(int[] source, int data) {
        int[] dest = new int[source.length + 1];
        copyArray(source, dest);
        dest[source.length] = data;
        return dest;
    }
}

что мне нужно изменить, чтобы вернуть дубликаты?
Brenden

Это следует задать как новый вопрос.
Willaien

0

Это был бы хороший способ найти повторяющиеся значения без использования Set.

public static <T> List<T> findDuplicates(List<T> list){

List<T> nonDistinctElements = new ArrayList<>();

  for(T s : list)
    if(list.indexOf(s) != list.lastIndexOf(s))
      if(!nonDistinctElements.contains(s))
        nonDistinctElements.add(s);

  return nonDistinctElements;
}

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

public static <T> void distinctList(List<T> list){

List<T> nonDistinctElements = new ArrayList<>();
for(T s : list)
  if(list.indexOf(s) != list.lastIndexOf(s))
    nonDistinctElements.add(s);

for(T nonDistinctElement : nonDistinctElements)
  if(list.indexOf(nonDistinctElement) != list.lastIndexOf(nonDistinctElement))
    list.remove(nonDistinctElement);
}

0

И версия, в которой используется commons-collections CollectionUtils.getCardinalityMapметод:

final List<Integer> values = Arrays.asList(1, 1, 2, 3, 3, 3);
final Map<Integer, Integer> cardinalityMap = CollectionUtils.getCardinalityMap(values);
System.out.println(cardinalityMap
            .entrySet()
            .stream().filter(e -> e.getValue() > 1)
            .map(e -> e.getKey())
            .collect(Collectors.toList()));

`` `


0

Как насчет этого кода -

public static void main(String[] args) {

    //Lets say we have a elements in array
    int[] a = {13,65,13,67,88,65,88,23,65,88,92};

    List<Integer> ls1 = new ArrayList<>();
    List<Integer> ls2 = new ArrayList<>();
    Set<Integer> ls3 = new TreeSet<>();

    //Adding each element of the array in the list      
    for(int i=0;i<a.length;i++) {
     {
    ls1.add(a[i]);
    }
    }

    //Iterating each element in the arrary
    for (Integer eachInt : ls1) {

    //If the list2 contains the iterating element, then add that into set<> (as this would be a duplicate element)
        if(ls2.contains(eachInt)) {
            ls3.add(eachInt);
        }
        else {ls2.add(eachInt);}

    }

    System.out.println("Elements in array or ls1"+ls1); 
    System.out.println("Duplicate Elements in Set ls3"+ls3);


}

0

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

используйте этот код (измените на нужный вам тип)

public Set<String> findDup(List<String> Duplicates){
    Set<String> returning = new HashSet<>();
    Set<String> nonreturning = new HashSet<>();
    Set<String> setup = new HashSet<>();
    for(String i:Duplicates){
        if(!setup.add( i )){
            returning.add( i );
        }else{
            nonreturning.add( i );
        }
    }
    Toast.makeText( context,"hello set"+returning+nonreturning+" size"+nonreturning.size(),Toast.LENGTH_SHORT ).show();
    return nonreturning;
}

0

Более общий метод как вариант https://stackoverflow.com/a/52296246

    /**
     * Returns a duplicated values found in given collection based on fieldClassifier
     *
     * @param collection given collection of elements
     * @param fieldClassifier field classifier which specifies element to check for duplicates(useful in complex objects).
     * @param <T> Type of element in collection
     * @param <K> Element which will be returned from method in fieldClassifier.
     * @return returns list of values that are duplocated.
     */
    public static <T, K> List<K> lookForDuplicates(List<T> collection, Function<? super T, ? extends K> fieldClassifier) {

        return collection.stream().collect(Collectors.groupingBy(fieldClassifier))
                         .entrySet()
                         .stream()
                         .filter(e -> e.getValue().size() > 1)
                         .map(Map.Entry::getKey)
                         .collect(Collectors.toList());
    }

-1

Если вы знаете максимальное значение (например, <10000), вы можете пожертвовать пространством ради скорости. Не могу вспомнить точное название этой техники.

псевдокод:

//does not handle case when mem allocation fails 
//probably can be extended to unknown values /larger values .
maybe by sorting first
public List<int> GetDuplicates(int max)
{   
    //allocate and clear memory to 0/false
    bit[] buckets=new bit[max]
    memcpy(buckets,0,max);
    //find duplicates
    List<int> result=new List<int>();
    foreach(int val in List)
    {
        if (buckets[val])
        {
            result.add(value);
        }
        else
        {
            buckets[val]=1;
        }
    }
    return  result
}

Я думаю, вам нужно «логическое» вместо «бит»? Вы выполнили свой код перед его публикацией? Это хорошее начало. Если вы посмотрите на HashSet (), то увидите, что это именно та реализация, которая вам нужна.
johnstosh

-1

Просто попробуйте это:

Пример значений списка: [1, 2, 3, 4, 5, 6, 4, 3, 7, 8] повторяющийся элемент [3, 4].

Collections.sort(list);
        List<Integer> dup = new ArrayList<>();
        for (int i = 0; i < list.size() - 1; i++) {
            if (list.get(i) == list.get(i + 1)) {
                if (!dup.contains(list.get(i + 1))) {
                    dup.add(list.get(i + 1));
                }
            }
        }
        System.out.println("duplicate item " + dup);

Вызов contains () для ArrayList () - дорогостоящая операция, поэтому вам следует подумать об использовании вместо этого Set. Вы увидите другие решения, использующие HashSet () или связанные версии.
johnstosh
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.