Identificar duplicados en una lista

119

Tengo una lista de tipo Integer, por ejemplo:

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

Me gustaría un método para devolver todos los duplicados, por ejemplo:

[1, 3]

¿Cuál es la mejor manera de hacer esto?

mas fresco
fuente
2
¿Se garantiza que la lista de entrada estará ordenada (como en su ejemplo)?
NPE
7
ordenar la lista, luego recorrerla, manteniendo los valores actuales y anteriores. si actual == anterior, tiene un duplicado.
mcfinnigan
No, la lista no está necesariamente ordenada.
más reciente el

Respuestas:

183

El método addde Setdevuelve un booleano si un valor ya existe (verdadero si no existe, falso si ya existe, consulte la documentación de Set ).

Así que repite todos los valores:

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
fuente
1
¿Por qué tiene setToReturn? ¿No puedes simplemente usar set1.add (yourInt) y devolver set1?
Phil
3
sí exactamente. Pero cuando un elemento solo está presente una vez en la lista especificada, el elemento también se agrega. Mire el ejemplo en la pregunta: Mi solución devolverá [1,3] ya que el número 2 se inserta en set1 pero no en setToReturn. Su solución devolvería [1,2,3] (que no es el requisito)
leifg
1
Le sugiero que use for (Integer yourInt, para evitar el boxeo y unboxing innecesarios, especialmente porque su entrada ya contiene Integers.
Hosam Aly
1
@JonasThelemann la idea general de un conjunto es que NO puede contener duplicados. por lo tanto: no importa la frecuencia con la que agregue 3, siempre terminará solo una vez.
leifg
1
Por cierto, en caso de HashSetque también tenga que considerar el factor de carga, por ejemplo, cuando especifica una capacidad inicial de 100, porque desea agregar esa cantidad de elementos, se redondea a la siguiente potencia de 2 ( 128), lo que implica que con el factor de carga predeterminado de 0.75f, el umbral de cambio de tamaño será 96, por lo que habrá un cambio de tamaño antes de agregar 100elementos. Afortunadamente, cambiar el tamaño ya no es tan caro. Con los JRE actualizados, el cambio de tamaño ya no es un refrito, los elementos simplemente se distribuyen entre sus dos posibles ubicaciones de resultados según el bit relevante.
Holger
50

También necesitaba una solución para esto. Usé la solución de leifg y la hice genérica.

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
fuente
1
Sé que esto es 3 años después, pero ¿por qué un LinkedHashedSet, es decir, por qué le importa el pedido?
Ahmad Ragab
4
@AhmadRagab tiene razón, LinkedHashSet no es necesario a menos que le importe el orden en que se encontraron los duplicados (que creo que hice en ese momento)
John Strickler
¡Gracias por seguir!
Ahmad Ragab
Si tiene tantos datos de entrada que desea utilizar esta solución óptima (en lugar de ordenar la entrada), también querrá preasignar el tamaño de los objetos HashSet (). Sin la preasignación, no obtiene el tiempo de inserción O (1) al insertar en el HashSet (). Esto se debe a que la matriz hash interna cambia de tamaño repetidamente. Luego, las inserciones promedian algo así como el tiempo O (log N). Esto significa que procesar todos los N elementos se convierte en O (N log N) cuando podría haber sido O (N).
johnstosh
39

Tomé la solución de John Strickler y la rehice para usar la API de flujos introducida en 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());
}
Sebastián
fuente
3
esto es un poco difícil de leer, ¿no? Estás produciendo un efecto secundario en la operación de transmisión, por lo que es un poco difícil razonar. Pero eso es solo yo pensando en estilo funcional. Sin embargo, es conciso y probablemente el camino más corto;).
froginvasion
Para listas grandes, ¿puede hacer que esto se ejecute en paralelo en varios subprocesos?
johnstosh
@froginvasion el distinct()método integrado también tiene estado. No puedo pensar en una operación distinta eficiente (O (n)) que no tenga estado.
wilmol
18

Aquí hay una solución que usa 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<>();

Solo mire si la frecuencia de este objeto está más de una vez en su lista. Luego llame a .distinct () para tener solo elementos únicos en su resultado

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
monigote de nieve
fuente
1
Esto es bueno en términos de legibilidad, pero REALMENTE malo para el rendimiento. Collections::frequencyEstá encendido). Es necesario revisar toda la colección para encontrar la frecuencia de un artículo. Y lo llamamos una vez para cada elemento de la colección, lo que hace estos fragmentos O(n^2). Notarás la diferencia en cualquier colección de más de un puñado de elementos. Nunca usaría esto en código real.
Pawan
13

solución 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());
بلال المصمودي
fuente
La lista de entrada se transforma en un mapa (agrupación por los mismos valores). luego los valores del mapa con un valor único se "eliminan", luego se asignan con la clave, luego la lista de la lista se transforma en una Lista
بلال المصمودي
solución hermosa y rápida, directamente modificable para filtrar en
captadores
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) );
    }

}

Obviamente, puede hacer lo que quiera con ellos (es decir, poner un Conjunto para obtener una lista única de valores duplicados) en lugar de imprimir ... Esto también tiene la ventaja de registrar la ubicación de los elementos duplicados.

Ashkan Aryan
fuente
7

Usando Guava en 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();
}
Philipp Paland
fuente
7

Esto también funciona:

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
fuente
Funciona, pero es bastante lento ya que llamar a remove () en una lista de arreglos es una búsqueda lineal.
johnstosh
cierto. Tenga en cuenta que si su entrada contiene muchos duplicados, el impacto en el rendimiento es menor que si solo hubiera unos pocos.
Adriaan Koster
6

Puedes usar algo como esto:

List<Integer> newList = new ArrayList<Integer>();
for(int i : yourOldList)
{
    yourOldList.remove(i);
    if(yourOldList.contains(i) && !newList.contains(i)) newList.add(i);
}
Ing.Fouad
fuente
2
Usar List aquí es muy ineficaz
Alexander Farber
2
Y no me hagas empezar a usar intcomo tipo de variable aquí. Significa que para cada iteración, un entero se desempaqueta una vez y un int se coloca en una caja cuatro veces.
Sean Patrick Floyd
1
Creo que puede obtener fácilmente una ConcurrentModificationException al intentar eliminar un elemento de la lista mientras lo itera
Jad B.
1
esto es 100% ConcurrentModificationException ya que itera sobre una lista y elimina elementos sobre la marcha.
theo231022
5

Lambas podría ser una solución

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
fuente
1
Funciona, pero ejecuta Collections.frequency para cada entrada y, por lo tanto, es lento.
arberg
4

Utilice un MultiMap para almacenar cada valor como un conjunto de clave / valor. Luego, recorra las claves en iteración y encuentre las que tengan varios valores.

Juan B
fuente
3

Si usa Eclipse Collections , esto funcionará:

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

Actualización: a partir de Eclipse Collections 9.2 ahora puede usarselectDuplicates

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

También puede usar colecciones primitivas para lograr esto:

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: Soy un comprometido con las colecciones de Eclipse.

Donald Raab
fuente
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
fuente
Me gusta esta respuesta, solo necesitaba agregar otra para guardar el duplicado en otra lista. gracias
Tiago Machado
2

Similar a algunas respuestas aquí, pero si desea encontrar duplicados basados ​​en alguna propiedad:

  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
fuente
1

crea a Map<Integer,Integer>, itera la lista, si un elemento está en el mapa, aumenta su valor, de lo contrario agrégalo al mapa con key = 1
itera el mapa y agrega a las listas todos los elementos 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);
        }

    }
amit
fuente
Esto es bastante bueno. Es la mejor solución si necesita saber cuántos duplicados había. Algunas notas: (1) no es necesario llamar a remove () antes de hacer put (). (2) Puede configurar LinkedList desde una matriz en lugar de usar repetidas llamadas add (). (3) Cuando val! = Null, puede sumar inmediatamente x al resultado. El resultado podría ser un conjunto o una lista, dependiendo de si desea llevar la cuenta del número de duplicados.
johnstosh
1

Versión compacta generada de la respuesta principal, también se agregó un cheque vacío y un tamaño de conjunto preasignado:

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
fuente
¿Necesitas el cheque cero? ¿New HashSet <> (0) devolverá el conjunto vacío sensible?
johnstosh
@johnstosh este código podría simplificarse, pero la comprobación de cero permite iniciar solo tempSetcon listSizecuando sea necesario. Esta es una optimización menor, pero me gusta.
Christophe Roussy
1

Tomé la respuesta de Sebastian y le agregué 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());
    }
Ashish Tyagi
fuente
1

Una alternativa segura para subprocesos es esta:

/**
 * 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;
}
Severo
fuente
0

Intente esto para encontrar elementos duplicados en la lista:

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
fuente
Sí, esto encuentra el conjunto, pero no encuentra la lista o el conjunto de los elementos que están duplicados.
johnstosh
0

Esto debería funcionar para ordenados y sin clasificar.

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
fuente
Llamar a contains () en la subList de ArrayList es costoso porque es una búsqueda lineal. Así que esto está bien para 10 artículos, pero no para 10 millones.
johnstosh
0

Este es un problema donde brillan las técnicas funcionales. Por ejemplo, la siguiente solución de F # es más clara y menos propensa a errores que la mejor solución imperativa de Java (y trabajo a diario con Java y F #).

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

Por supuesto, esta pregunta es sobre Java. Entonces, mi sugerencia es adoptar una biblioteca que aporte características funcionales a Java. Por ejemplo, podría resolverse usando mi propia biblioteca de la siguiente manera (y hay varias otras que vale la pena ver también):

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
fuente
Y luego ves cuánto Java realmente apesta en la programación funcional. Un problema tan simple, tan difícil de expresar lo que quieres en 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;
    }

}
Samrat Roy
fuente
Implementación sin usar clases de colección. Pero necesita poca mejora en el ciclo. La ayuda de voluntariado es apreciable. La salida de arriba se ve como -> 2 3 4 6 8 10 11 12
Samrat Roy
Para que esto se ejecute en una menor cantidad de tiempo, debe utilizar una estructura de datos basada en hash para realizar un seguimiento de los duplicados. Es por eso que ve las otras soluciones que usan HashSet (): está integrado en Java.
johnstosh
@johnstosh Sí, lo sé, pero estaba pensando en hacerlo sin usar colecciones, por eso lo mencioné en mi comentario.Como ves, he comentado mucho antes de febrero de 2017, [hay técnicas en las que no tienes que usar colecciones en absoluto con menor complejidad de tiempo] geeksforgeeks.org/… .He probado ese programa sin conocer las prácticas de DS y Algo. No tienes que votarme por eso ... de todos modos Gracias.
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
fuente
¿Qué necesito cambiar para que esto devuelva los duplicados?
Brenden
Esto debería plantearse como una nueva pregunta.
willaien
0

Este sería un buen método para encontrar valores duplicados, sin usar 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;
}

Y digamos que desea un método que le devuelva una lista distinta, es decir, si pasa una lista donde los elementos están ocurriendo más de una vez, obtendrá una lista con elementos distintos.

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
fuente
0

Y versión que usa el commons-collections CollectionUtils.getCardinalityMapmétodo:

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
fuente
0

¿Qué tal este código?

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
fuente
0

por si acaso para aquellos que también quieran incluir tanto los duplicados como los no duplicados. Básicamente, la respuesta es similar a la respuesta correcta, pero en lugar de regresar de if not part, devuelve la otra parte

use este código (cambie al tipo que necesita)

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

fuente
0

Método más genérico como variante de 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
fuente
-1

Si conoce el valor máximo (por ejemplo, <10000), podría sacrificar espacio por velocidad. No recuerdo el nombre exacto de esta técnica.

pseudo código:

//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
fuente
Creo que quieres "booleano" en lugar de "bit". ¿Ejecutó su código antes de publicarlo? Este es un buen comienzo. Si echa un vistazo a HashSet (), verá que es la implementación de 'cubos' lo que desea.
johnstosh
-1

Intenta esto:

Ejemplo si los valores de la lista son: [1, 2, 3, 4, 5, 6, 4, 3, 7, 8] elemento duplicado [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);
Aprendizaje del usuario
fuente
Invocar contains () en una ArrayList () es una operación costosa, por lo que debería considerar usar un Set en su lugar. Verá otras soluciones usando HashSet () o versiones vinculadas de él.
johnstosh