Zidentyfikuj duplikaty na liście

120

Mam listę typu Integer np:

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

Chciałbym, aby metoda zwracała wszystkie duplikaty np:

[1, 3]

Jaki jest najlepszy sposób, aby to zrobić?

najświeższe
źródło
2
Czy lista wejściowa ma być posortowana (jak w twoim przykładzie)?
NPE
7
posortuj listę, a następnie przejrzyj ją, zachowując aktualne i wcześniejsze wartości. jeśli aktualny == przed masz duplikat.
mcfinnigan,
Nie, lista niekoniecznie jest posortowana.
najświeższy

Odpowiedzi:

183

Metoda addz SetZwraca wartość logiczną, czy wartość już istnieje (true, jeśli nie istnieje, fałsz, jeśli już istnieje, patrz zestaw dokumentacji ).

Po prostu powtórz wszystkie wartości:

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;
}
leifg
źródło
1
Dlaczego masz setToReturn? Czy nie możesz po prostu użyć set1.add (yourInt) i zwrócić set1?
Phil,
3
tak, dokładnie. Ale jeśli element występuje tylko raz na określonej liście, element jest również dodawany. Spójrz na przykład w pytaniu: Moje rozwiązanie zwróci [1,3], ponieważ liczba 2 jest wstawiona do set1, ale nie do setToReturn. Twoje rozwiązanie
zwróciłoby
1
Sugeruję, abyś użył for (Integer yourInt, aby uniknąć niepotrzebnego pakowania i rozpakowywania, zwłaszcza, że ​​twoje wejście zawiera już Integers.
Hosam Aly
1
@JonasThelemann cała idea zestawu polega na tym, że NIE może zawierać duplikatów. dlatego: bez względu na to, jak często będziesz dodawać 3, zawsze skończy się tylko raz.
leifg
1
Nawiasem mówiąc, w przypadku HashSetciebie również musisz wziąć pod uwagę współczynnik obciążenia, np. Kiedy określasz pojemność początkową wynoszącą 100, ponieważ chcesz dodać tę liczbę elementów, zostanie ona zaokrąglona do następnej potęgi 2 ( 128), co oznacza, że z domyślnym współczynnikiem obciążenia 0.75frównym próg zmiany rozmiaru będzie 96, więc zmiana rozmiaru nastąpi przed dodaniem 100elementów. Na szczęście zmiana rozmiaru nie jest już taka droga. W aktualnych środowiskach JRE zmiana rozmiaru nie jest już ponownie mieszana, elementy są po prostu rozdzielane między dwie możliwe lokalizacje wyników na podstawie odpowiedniego bitu.
Holger
50

Potrzebowałem również rozwiązania tego problemu. Użyłem rozwiązania Leifga i uczyniłem go ogólnym.

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;
}
John Strickler
źródło
1
Wiem, że to 3 lata później, ale dlaczego LinkedHashedSet, czyli dlaczego zależy Ci na zamówieniu?
Ahmad Ragab
4
@AhmadRagab masz rację, LinkedHashSet nie jest wymagany, chyba że zależy Ci na kolejności znalezienia duplikatów (co myślę, że wtedy zrobiłem)
John Strickler
Dziękuję za kontakt!
Ahmad Ragab,
Jeśli masz tak dużo danych wejściowych, że chcesz użyć tego optymalnego rozwiązania (zamiast sortować dane wejściowe), będziesz również chciał wstępnie przydzielić rozmiar obiektów HashSet (). Bez prealokacji nie otrzymasz czasu wstawiania O (1) podczas wstawiania do HashSet (). Dzieje się tak, ponieważ wewnętrzna tablica skrótów jest wielokrotnie zmieniana. Wstawki są następnie uśredniane do czasu około O (log N). Oznacza to, że przetwarzanie wszystkich N elementów staje się O (N log N), podczas gdy mogło to być O (N).
johnstosh
39

Wziąłem rozwiązanie Johna Stricklera i przerobiłem je, aby korzystało z interfejsu API strumieni wprowadzonego w 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());
}
Sebastian
źródło
3
to trochę trudne do odczytania, prawda? Robisz efekt uboczny w operacji strumienia, przez co trudno o tym myśleć. Ale to tylko ja myślę o funkcjonalnym stylu. Jest zwięzła i chyba najkrótsza;).
froginvasion
W przypadku dużych list można wykonać to równolegle w wielu wątkach?
johnstosh
@froginvasion, wbudowana distinct()metoda jest również stanowa. Nie mogę wymyślić wydajnej (O (n)) odrębnej operacji, która nie jest stanowa.
wilmol
18

Oto rozwiązanie wykorzystujące strumienie z Javą 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<>();

Po prostu spójrz, czy częstotliwość tego obiektu jest więcej niż raz na liście. Następnie wywołaj .distinct (), aby mieć w wyniku tylko unikalne elementy

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
bałwan
źródło
1
To jest dobre pod względem czytelności, ale NAPRAWDĘ źle wpływa na wydajność. Collections::frequencyjest O (n). Aby znaleźć częstotliwość danego elementu, musi przejść przez całą kolekcję. I nazywamy to raz dla każdego elementu w kolekcji, co tworzy te fragmenty O(n^2). Zauważysz różnicę w każdym zbiorze obejmującą więcej niż kilka elementów. Nigdy nie użyłbym tego w rzeczywistym kodzie.
Pawan
14

podstawowe rozwiązanie 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());
بلال المصمودي
źródło
lista wejściowa jest przekształcana w mapę (grupowana według tych samych wartości). następnie wartości mapy z unikalną wartością są „usuwane”, następnie mapowane są za pomocą klucza, a następnie lista listy jest przekształcana w Listę
بلال المصمودي
piękne i szybkie rozwiązanie, bezpośrednio modyfikowalne do filtrowania na określonych
getterach
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) );
    }

}

Oczywiście możesz z nimi zrobić, co chcesz (np. Umieścić w zestawie, aby uzyskać unikalną listę zduplikowanych wartości) zamiast drukowania ... Ma to również tę zaletę, że rejestruje lokalizację zduplikowanych elementów.

Ashkan Aryan
źródło
7

Używanie guawy w Javie 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();
}
Philipp Paland
źródło
7

Działa to również:

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);
}
Adriaan Koster
źródło
Działa, ale jest raczej powolny, ponieważ wywołanie funkcji remove () na liście tablic jest przeszukiwaniem liniowym.
johnstosh
prawdziwe. Zwróć uwagę, że jeśli dane wejściowe zawierają wiele duplikatów, efekt wydajności jest mniejszy, niż gdyby było ich tylko kilka.
Adriaan Koster
6

Możesz użyć czegoś takiego:

List<Integer> newList = new ArrayList<Integer>();
for(int i : yourOldList)
{
    yourOldList.remove(i);
    if(yourOldList.contains(i) && !newList.contains(i)) newList.add(i);
}
Eng. Fouad
źródło
2
Korzystanie z listy tutaj jest bardzo nieskuteczne
Alexander Farber,
2
I nie zaczynaj mnie tutaj używać intjako typu zmiennej. Oznacza to, że dla każdej iteracji liczba całkowita jest rozpakowywana raz, a liczba int jest pakowana cztery razy!
Sean Patrick Floyd
1
Myślę, że możesz łatwo uzyskać ConcurrentModificationException podczas próby usunięcia elementu z listy podczas iteracji po nim
Jad B.
1
jest to wyjątek 100% ConcurrentModificationException, ponieważ wykonujesz iterację po liście i usuwasz elementy w locie.
theo231022
5

Rozwiązaniem mogą być jagnięciny

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());
APA
źródło
1
Działa, ale uruchamia Collections.frequency dla każdego wpisu i dlatego jest powolny.
arberg
4

Użyj MultiMap, aby zapisać każdą wartość jako zestaw klucz / wartość. Następnie przejrzyj klucze i znajdź te z wieloma wartościami.

John B.
źródło
3

Jeśli używasz kolekcji Eclipse , zadziała to:

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

Aktualizacja: od Eclipse Collections 9.2 możesz teraz używać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);

Aby to osiągnąć, możesz również użyć kolekcji prymitywnych:

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

Uwaga: jestem promotorem Eclipse Collections.

Donald Raab
źródło
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);

    }

}
Baisakha Chauhan
źródło
Podoba mi się ta odpowiedź, wystarczy dodać jeszcze jedno, aby zapisać duplikat na innej liście. dzięki
Tiago Machado
2

Podobne do niektórych odpowiedzi tutaj, ale jeśli chcesz znaleźć duplikaty na podstawie jakiejś właściwości:

  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());
  }
wilmol
źródło
1

utwórz Map<Integer,Integer>, iteruj listę, jeśli element jest na mapie, zwiększ jego wartość, w przeciwnym razie dodaj go do mapy za pomocą klucza = 1
iteruj mapę i dodaj do list wszystkie elementy za pomocą klucza> = 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);
        }

    }
dobrze
źródło
To jest całkiem niezłe. To najlepsze rozwiązanie, jeśli chcesz wiedzieć, ile było duplikatów. Kilka uwag: (1) nie musisz wywoływać funkcji remove () przed wykonaniem metody put (). (2) Możesz skonfigurować LinkedList z tablicy zamiast używać powtarzających się wywołań add (). (3) Gdy val! = Null, możesz natychmiast dodać x do wyniku. Rezultatem może być zestaw lub lista, w zależności od tego, czy chcesz liczyć liczbę duplikatów.
johnstosh
1

Kompaktowa uogólniona wersja najlepszej odpowiedzi, dodano również pusty czek i wstępnie przydzielony rozmiar zestawu:

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;
  }
Christophe Roussy
źródło
Czy potrzebujesz zerowego czeku? Czy nowy zestaw HashSet <> (0) zwróci rozsądny pusty zestaw?
johnstosh
@johnstosh ten kod można uprościć, ale sprawdzenie zerowej wartości pozwala na zainicjowanie tempSetwith tylko listSizewtedy, gdy jest to konieczne. To drobna optymalizacja, ale mi się podoba.
Christophe Roussy
1

Wziąłem odpowiedź Sebastiana i dodałem do niej 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());
    }
Ashish Tyagi
źródło
1

Oto bezpieczna dla wątków alternatywa:

/**
 * 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;
}
Ponury
źródło
0

Spróbuj tego, aby znaleźć duplikaty pozycji na liście:

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()); 
} 
Tushar Ahirrao
źródło
Tak, to znajduje zestaw, ale nie znajduje listy ani zestawu tych elementów, które są duplikatami.
johnstosh
0

Powinno to działać w przypadku posortowanych i nieposortowanych.

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));
}
James DW
źródło
Wywołanie funkcji include () na subList tablicy ArrayList jest kosztowne, ponieważ jest to wyszukiwanie liniowe. Więc to jest w porządku dla 10 pozycji, ale nie dla 10 milionów.
johnstosh
0

To problem, w którym błyszczą techniki funkcjonalne. Na przykład poniższe rozwiązanie F # jest bardziej przejrzyste i mniej podatne na błędy niż najlepsze imperatywne rozwiązanie Java (i pracuję codziennie zarówno z Javą, jak i F #).

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

Oczywiście to pytanie dotyczy Javy. Dlatego proponuję przyjęcie biblioteki, która wprowadza funkcje funkcjonalne do Javy. Na przykład można to rozwiązać za pomocą mojej własnej biblioteki w następujący sposób (i jest kilka innych wartych obejrzenia):

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();
    }
});
Stephen Swensen
źródło
A potem widzisz, ile Java nadal jest do bani w programowaniu funkcjonalnym. Taki prosty problem, tak trudno wyrazić to, czego chcesz w Javie.
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;
    }

}
Samrat Roy
źródło
Wdrażanie bez użycia klas Collection.Ale wymaga niewielkiej poprawy w pętli.Pomoc wolontariatu jest znaczna.Wyjście dla powyższego wygląda następująco -> 2 3 4 6 8 10 11 12
Samrat Roy
Aby wykonać to w krótszym czasie, musisz użyć struktury danych opartej na skrótach, aby śledzić duplikaty. Dlatego widzisz inne rozwiązania wykorzystujące HashSet () - jest on wbudowany w Javę.
johnstosh
@johnstosh Tak, wiem o tym, ale myślałem o zrobieniu tego bez korzystania z Kolekcji, dlatego wspomniałem w moim komentarzu. Jak widzisz, skomentowałem dużo przed lutym 2017 r. [są techniki, w których w ogóle nie musisz używać kolekcji z mniejszą złożonością czasową] geeksforgeeks.org/…. Wypróbowałem ten program bez znajomości praktyk DS i Algo. Nie musisz mnie za to negatywnie oceniać ... zawsze dzięki.
Samrat Roy
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
źródło
co muszę zmienić, aby zwrócić duplikaty?
Brenden
To powinno zostać zadane jako nowe pytanie.
willaien
0

To byłaby dobra metoda znajdowania zduplikowanych wartości bez używania 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;
}

Powiedzmy, że potrzebujesz metody, która zwraca odrębną listę, tj. Jeśli przekażesz listę, na której elementy występują więcej niż raz, otrzymasz listę z różnymi elementami.

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);
}
Aayush Shrivastava
źródło
0

I wersja, która używa commons-collections CollectionUtils.getCardinalityMap metodę:

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

`` ''

panurg
źródło
0

A co z tym kodem -

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


}
Karthik Deepan
źródło
0

na wszelki wypadek dla tych, które również chcą uwzględnić zarówno duplikaty, jak i nie duplikaty. w zasadzie odpowiedź jest podobna do poprawnej odpowiedzi, ale zamiast wracać z, jeśli nie części, zwracasz inną część

użyj tego kodu (zmień na typ, który potrzebujesz)

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

źródło
0

Bardziej ogólna metoda jako wariant 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());
    }
Igor Maculewicz
źródło
-1

Jeśli znasz maksymalną wartość (na przykład <10000), możesz poświęcić miejsce na rzecz prędkości. Nie pamiętam dokładnej nazwy tej techniki.

pseudo kod:

//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
}
Alex
źródło
Myślę, że chcesz „boolean” zamiast „bit”? Czy wykonałeś kod przed wysłaniem? To dobry początek. Jeśli spojrzysz na HashSet (), zobaczysz, że jest to implementacja „wiader”, której potrzebujesz.
johnstosh
-1

Po prostu spróbuj tego:

Przykład, jeśli wartości listy to: [1, 2, 3, 4, 5, 6, 4, 3, 7, 8] zduplikowany element [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);
Nauka użytkownika
źródło
Wywoływanie funkcji include () na tablicy ArrayList () jest kosztowną operacją, dlatego należy zamiast tego rozważyć użycie metody Set. Zobaczysz inne rozwiązania wykorzystujące HashSet () lub połączone wersje.
johnstosh