Identifica i duplicati in un elenco


120

Ho un elenco di tipo Integer, ad esempio:

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

Vorrei un metodo per restituire tutti i duplicati, ad esempio:

[1, 3]

Qual è il modo migliore per farlo?


2
È garantito che l'elenco di input sia ordinato (come nel tuo esempio)?
NPE

7
ordina l'elenco, quindi cammina, mantenendo i valori correnti e precedenti. se corrente == prima hai un duplicato.
mcfinnigan

No, l'elenco non è necessariamente ordinato.
più fresco

Risposte:


183

Il metodo adddi Setrestituisce un valore booleano se un valore esiste già (true se non esiste, false se esiste già, vedere la documentazione di Set ).

Quindi basta scorrere tutti i valori:

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
Perché hai setToReturn? Non puoi semplicemente usare set1.add (yourInt) e restituire set1?
Phil

3
si, esattamente. Ma quando un elemento è presente solo una volta nell'elenco specificato, viene aggiunto anche l'elemento. Guarda l'esempio nella domanda: La mia soluzione restituirà [1,3] poiché il numero 2 è inserito in set1 ma non in setToReturn. La tua soluzione restituirà [1,2,3] (che non è il requisito)
leifg

1
Ti suggerisco di usare for (Integer yourInt, per evitare inutili boxe e unboxing, soprattutto perché il tuo input contiene già Integers.
Hosam Aly

1
@JonasThelemann l'idea di un set è che NON può contenere duplicati. quindi: non importa quanto spesso aggiungerai 3, finirà sempre solo una volta.
leifg

1
A proposito, nel caso in cui HashSetsi debba considerare anche il fattore di carico, ad esempio quando si specifica una capacità iniziale di 100, poiché si desidera aggiungere quel numero di elementi, viene arrotondato alla successiva potenza di 2 ( 128), il che implica che con il fattore di carico predefinito di 0.75f, la soglia di ridimensionamento sarà 96, quindi ci sarà un ridimensionamento prima di aver aggiunto 100elementi. Per fortuna, il ridimensionamento non è più così costoso. Con i JRE aggiornati, il ridimensionamento non è più il rehashing, gli elementi vengono semplicemente distribuiti tra le due possibili posizioni dei risultati in base al bit pertinente.
Holger

50

Avevo bisogno di una soluzione anche a questo. Ho usato la soluzione di leifg e l'ho resa generica.

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
So che sono passati 3 anni, ma perché un LinkedHashedSet, cioè perché ti interessa l'ordine?
Ahmad Ragab

4
@AhmadRagab hai ragione, LinkedHashSet non è richiesto a meno che non ti interessi dell'ordine in cui sono stati trovati i duplicati (cosa che penso di aver fatto all'epoca)
John Strickler

Grazie per il seguito!
Ahmad Ragab

Se hai così tanti dati di input che desideri utilizzare questa soluzione ottimale (invece di ordinare l'input), allora ti consigliamo di pre-allocare la dimensione degli oggetti HashSet (). Senza la preallocazione, non si ottiene il tempo di inserimento O (1) quando si inserisce in HashSet (). Questo perché l'array hash interno viene ridimensionato ripetutamente. Gli inserti quindi media a qualcosa come O (log N) tempo. Ciò significa che l'elaborazione di tutti gli N elementi diventa O (N log N) quando avrebbe potuto essere O (N).
johnstosh

39

Ho preso la soluzione di John Strickler e l'ho rifatta per utilizzare l'API dei flussi introdotta in 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
questo è un po 'difficile da leggere, no? Stai facendo un effetto collaterale nel funzionamento del flusso, rendendo un po 'difficile ragionare. Ma sono solo io che penso allo stile funzionale. È conciso e probabilmente il modo più breve;).
froginvasion

Per elenchi di grandi dimensioni puoi farlo eseguire in parallelo su più thread?
johnstosh

@froginvasion anche il distinct()metodo integrato è stateful. Non riesco a pensare a un'operazione distinta efficiente (O (n)) che non sia stateful.
wilmol

18

Ecco una soluzione che utilizza Streams con 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<>();

Guarda solo se la frequenza di questo oggetto è più di una volta nella tua lista. Quindi chiama .distinct () per avere solo elementi unici nel tuo risultato

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
Questo è buono in termini di leggibilità, ma è DAVVERO negativo per le prestazioni. Collections::frequencyè O (n). Deve esaminare l'intera raccolta per trovare la frequenza di un elemento. E lo chiamiamo una volta per ogni elemento nella raccolta, il che rende questi frammenti O(n^2). Noterai la differenza in qualsiasi raccolta di più di una manciata di elementi. Non lo userei mai nel codice reale.
Pawan

14

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

la lista di input viene trasformata in una mappa, (raggruppamento per stessi valori). quindi i valori della mappa con un valore univoco vengono "cancellati", quindi la mappa utilizzando il tasto, quindi l'elenco dell'elenco viene trasformato in un elenco
بلال المصمودي

soluzione bella e veloce, direttamente modificabile in filtraggio su specifici getter dell'articolo
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) );
    }

}

Ovviamente puoi fare quello che vuoi con loro (cioè mettere in un Set per ottenere un elenco univoco di valori duplicati) invece di stampare ... Questo ha anche il vantaggio di registrare anche la posizione degli elementi duplicati.


7

Utilizzo di Guava su 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

Funziona anche:

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

Funziona, ma è piuttosto lento poiché chiamare remove () su un elenco di array è una ricerca lineare.
johnstosh

vero. Tieni presente che se il tuo input contiene molti duplicati, il rendimento è minore che se ce ne fossero solo pochi.
Adriaan Koster

6

Puoi usare qualcosa del genere:

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

2
L'utilizzo dell'elenco qui è molto inefficace
Alexander Farber,

2
E non farmi iniziare a usare intcome tipo di variabile qui. Significa che per ogni singola iterazione, un intero viene unboxed una volta e un int viene inscatolato quattro volte!
Sean Patrick Floyd

1
Penso che tu possa facilmente ottenere un'eccezione ConcurrentModificationException quando provi a rimuovere un elemento dall'elenco mentre lo ripeti
Jad B.

1
questo è 100% ConcurrentModificationException poiché si itera su un elenco e si rimuovono elementi al volo.
theo231022

5

Lambas potrebbe essere una soluzione

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
Funziona, ma esegue Collections.frequency per ogni voce ed è quindi lento.
arberg

4

Utilizzare una MultiMap per memorizzare ogni valore come set di chiavi / valori. Quindi scorrere le chiavi e trovare quelle con più valori.


3

Se utilizzi le collezioni Eclipse , funzionerà:

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

Aggiornamento: a partire da Eclipse Collections 9.2 ora puoi usareselectDuplicates

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

Puoi anche usare raccolte primitive per ottenere ciò:

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

Nota: sono un committer per le collezioni 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);

    }

}

Mi piace questa risposta, dovevo solo aggiungerne un'altra per salvare il duplicato in un altro elenco. grazie
Tiago Machado

2

Simile ad alcune risposte qui, ma se vuoi trovare duplicati basati su alcune proprietà:

  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

crea una Map<Integer,Integer>, itera la lista, se un elemento è nella mappa, aumenta il suo valore, altrimenti aggiungila alla mappa con key = 1
itera la mappa, e aggiungi alle liste tutti gli elementi con key> = 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);
        }

    }

Questo è abbastanza buono. È la soluzione migliore se hai bisogno di sapere quanti duplicati c'erano. Alcune note: (1) non è necessario chiamare remove () prima di eseguire put (). (2) È possibile impostare LinkedList da un array invece di utilizzare ripetute chiamate add (). (3) Quando val! = Null, potresti aggiungere immediatamente x al risultato. Il risultato potrebbe essere un set o un elenco a seconda che si desideri tenere il conteggio del numero di duplicati.
johnstosh

1

Versione compatta generata della risposta principale, aggiunta anche di un segno di spunta vuoto e dimensioni dell'insieme preallocate:

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

Hai bisogno del controllo zero? Il nuovo HashSet <> (0) restituirà il set vuoto ragionevole?
johnstosh

@johnstosh questo codice potrebbe essere semplificato, ma il controllo di zero consente di inizializzare solo tempSetcon listSizequando necessario. Questa è un'ottimizzazione minore ma mi piace.
Christophe Roussy

1

Ho preso la risposta di Sebastian e vi ho aggiunto un 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

Un'alternativa thread-safe è questa:

/**
 * 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

Prova questo per trovare gli elementi duplicati nell'elenco:

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

Sì, questo trova il set, ma non trova l'elenco o il set di quegli elementi che sono duplicati.
johnstosh

0

Questo dovrebbe funzionare per ordinati e non ordinati.

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

La chiamata contains () nella sottoelenco di ArrayList è costosa perché è una ricerca lineare. Quindi va bene per 10 articoli, ma non per 10 milioni.
johnstosh

0

Questo è un problema in cui brillano le tecniche funzionali. Ad esempio, la seguente soluzione F # è più chiara e meno soggetta a bug rispetto alla migliore soluzione Java imperativa (e lavoro quotidianamente con Java e F #).

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

Naturalmente, questa domanda riguarda Java. Quindi il mio suggerimento è di adottare una libreria che apporti funzionalità funzionali a Java. Ad esempio, potrebbe essere risolto utilizzando la mia libreria come segue (e ce ne sono molte altre là fuori che vale la pena guardare):

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

E poi vedi quanto Java in realtà fa ancora schifo alla programmazione funzionale. Un problema così semplice, così difficile da esprimere ciò che vuoi in 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;
    }

}

Implementare senza usare le classi Collection.Ma necessita di piccoli miglioramenti nel loop.L'aiuto del volontariato è apprezzabile.L'output per sopra assomiglia a -> 2 3 4 6 8 10 11 12
Samrat Roy

Per fare in modo che venga eseguito in un tempo minore, è necessario utilizzare una struttura di dati basata su hash per tenere traccia dei duplicati. Ecco perché vedi le altre soluzioni che utilizzano HashSet (): è integrato in Java.
johnstosh

@johnstosh Sì, lo so, ma stavo pensando di farlo senza usare le raccolte, ecco perché l'ho menzionato nel mio commento.Come vedi, ho commentato molto prima di febbraio 2017, [ci sono tecniche in cui non devi usare affatto le raccolte con minore complessità temporale] geeksforgeeks.org/… .Ho provato quel programma senza conoscere le pratiche DS e Algo. Non devi farmi un voto negativo per questo .. comunque Grazie.
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;
    }
}

cosa devo cambiare per restituire i duplicati?
Brenden

Questa dovrebbe essere una nuova domanda.
willaien

0

Questo sarebbe un buon metodo per trovare valori duplicati, senza usare 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;
}

E diciamo che vuoi un metodo che ti restituisca un elenco distinto, cioè se passi un elenco in cui gli elementi si verificano più di una volta, otterrai un elenco con elementi distinti.

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

E la versione che utilizza il commons-collections CollectionUtils.getCardinalityMapmetodo:

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

Che ne dici di questo codice -

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

per ogni evenienza per coloro che vogliono includere anche i duplicati e i non duplicati. fondamentalmente la risposta è simile alla risposta corretta ma invece di tornare dalla parte se non si restituisce la parte altrimenti

usa questo codice (cambia nel tipo che ti serve)

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

Metodo più generico come variante di 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

Se conosci il valore massimo (ad esempio <10000) potresti sacrificare lo spazio per la velocità. Non ricordo il nome esatto di questa tecnica.

pseudo codice:

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

Penso che vuoi "booleano" invece di "bit"? Hai eseguito il codice prima di pubblicarlo? Questo è un buon inizio. Se dai un'occhiata a HashSet (), vedrai che è l'implementazione dei "bucket" che desideri.
johnstosh

-1

Prova questo:

Esempio se i valori dell'elenco sono: [1, 2, 3, 4, 5, 6, 4, 3, 7, 8] elemento duplicato [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);

Invocare contains () su un ArrayList () è un'operazione costosa, quindi dovresti prendere in considerazione l'utilizzo di un Set. Vedrai altre soluzioni che utilizzano HashSet () o versioni collegate di esso.
johnstosh
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.