¿Cómo elimino elementos repetidos de ArrayList?

Respuestas:

991

Si no desea duplicados en un Collection, debe considerar por qué está utilizando un Collectionque permite duplicados. La forma más fácil de eliminar elementos repetidos es agregar el contenido a Set(que no permitirá duplicados) y luego agregar la parte Setposterior a ArrayList:

Set<String> set = new HashSet<>(yourList);
yourList.clear();
yourList.addAll(set);

Por supuesto, esto destruye el orden de los elementos en el ArrayList.

jonathan-stafford
fuente
261
Consulte también LinkedHashSet, si desea retener el pedido.
volea el
3
@Chetan encuentra todos los duplicados de ArrayList en O (n), es importante tener correctamente definido el método igual en los objetos que tiene en la lista (no hay problema para los números): public Set<Object> findDuplicates(List<Object> list) { Set<Object> items = new HashSet<Object>(); Set<Object> duplicates = new HashSet<Object>(); for (Object item : list) { if (items.contains(item)) { duplicates.add(item); } else { items.add(item); } } return duplicates; }
Ondrej Bozek
44
Una buena práctica sería definir variables utilizando los tipos de interfaz Listy Set(en lugar de los tipos de implementación ArrayListy HashSetcomo en su ejemplo).
Jonik
33
Puede limpiar esto usando en new HashSet(al)lugar de inicializarlo para vaciarlo y llamarlo addAll.
cenizas999
1
¿Puedo agregar reglas para configurar lo que está duplicado para mí? Por ejemplo: cuando mi Objecttiene varios valores si dos de ellos se repiten, los considero duplicados (otros valores pueden ser diferentes) y uso Set.
jean d'arme
290

Si bien la conversión ArrayLista a HashSetelimina eficazmente los duplicados, si necesita preservar el orden de inserción, prefiero sugerirle que use esta variante

// list is some List of Strings
Set<String> s = new LinkedHashSet<>(list);

Luego, si necesita recuperar una Listreferencia, puede usar nuevamente el constructor de conversión.

abahgat
fuente
10
¿LinkedHashSet ofrece alguna garantía sobre cuál de varios duplicados se mantiene de la lista? Por ejemplo, si las posiciones 1, 3 y 5 son duplicados en la lista original, ¿podemos suponer que este proceso eliminará 3 y 5? ¿O tal vez eliminar 1 y 3? Gracias.
Matt Briançon
16
@ Matt: sí, eso garantiza. Los documentos dicen: "Esta lista vinculada define el orden de iteración, que es el orden en que se insertaron los elementos en el conjunto (orden de inserción). Tenga en cuenta que el orden de inserción no se ve afectado si un elemento se vuelve a insertar en el conjunto".
abahgat
Muy interesante. Tengo una situación diferente aquí. No estoy tratando de ordenar String, sino otro objeto llamado AwardYearSource. Esta clase tiene un atributo int llamado año. Así que quiero eliminar duplicados según el año. es decir, si hay un año 2010 mencionado más de una vez, quiero eliminar ese objeto AwardYearSource. ¿Cómo puedo hacer eso?
WowBow
@WowBow Por ejemplo, puede definir el objeto Wrapper que contiene AwardYearSource. Y defina este objeto Wrapper igual método basado en el campo de año AwardYearSources. Luego puede usar Set con estos objetos Wrapper.
Ondrej Bozek
@WowBow o implemente Comparable / Comparator
shrini1000
134

En Java 8:

List<String> deduped = list.stream().distinct().collect(Collectors.toList());

Tenga en cuenta que el contrato hashCode-equals para los miembros de la lista debe respetarse para que el filtrado funcione correctamente.

Vitalii Fedorenko
fuente
1
¿Cómo hago esto para distinguir entre mayúsculas y minúsculas?
StackFlowed
@StackFlowed Si no necesita preservar el orden de la lista, puede addAllhacerlo new TreeSet<String>(String.CASE_INSENSITIVE_ORDER). El primer elemento agregado permanecerá en el conjunto, por lo que si su lista contiene "Perro" y "perro" (en ese orden) TreeSet, contendrá "Perro". Si se debe preservar el orden, antes de la línea de la respuesta list.replaceAll(String::toUpperCase);.
Paul
1
Recibo este error: tipos incompatibles: List <Object> no se puede convertir en List <String>
Samir
Esta es una solución simple en general, pero ¿cómo se eliminan los duplicados de una Arraylist de int []?
Programador de Nooby el
56

Supongamos que tenemos una lista de me Stringgusta:

List<String> strList = new ArrayList<>(5);
// insert up to five items to list.        

Entonces podemos eliminar elementos duplicados de múltiples maneras.

Antes de Java 8

List<String> deDupStringList = new ArrayList<>(new HashSet<>(strList));

Nota: Si queremos mantener el orden de inserción, entonces debemos usarLinkedHashSet en lugar deHashSet

Usando guayaba

List<String> deDupStringList2 = Lists.newArrayList(Sets.newHashSet(strList));

Usando Java 8

List<String> deDupStringList3 = strList.stream().distinct().collect(Collectors.toList());

Nota: En caso de que queramos recopilar el resultado en una implementación de lista específica, por ejemplo LinkedList, podemos modificar el ejemplo anterior como:

List<String> deDupStringList3 = strList.stream().distinct()
                 .collect(Collectors.toCollection(LinkedList::new));

También podemos usarlo parallelStreamen el código anterior, pero es posible que no proporcione los beneficios de rendimiento esperados. Mira esta pregunta para más.

akhil_mittal
fuente
Sí, cuando escribí mis comentarios anteriores, tuve la impresión de que parallel streamssiempre obtendría un mejor rendimiento. Pero es un mito. Más tarde aprendí que hay ciertos escenarios en los que deberían usarse flujos paralelos. En este escenario, las secuencias paralelas no ofrecerán un mejor rendimiento. y sí, las secuencias paralelas pueden no dar los resultados deseados en algunos casos. List<String> deDupStringList3 = stringList.stream().map(String::toLowerCase).distinct().collect(Collectors.toList());debería ser la solución adecuada en este caso
Diablo
53

Si no quieres duplicados, usa un Set en lugar de a List. Para convertir a Lista Setpuede usar el siguiente código:

// list is some List of Strings
Set<String> s = new HashSet<String>(list);

Si es realmente necesario, puede usar la misma construcción para convertir un Setrespaldo en a List.

Benno Richters
fuente
Del mismo modo, en la parte inferior del hilo, he dado una respuesta donde estoy usando Establecer para objeto personalizado. En un caso, si alguien tiene un objeto personalizado como "Contacto" o "Estudiante" puede usar esa respuesta que funciona bien para mí.
Muhammad Adil
El problema surge cuando tienes que acceder específicamente a un elemento. Por ejemplo, al vincular un objeto a una vista de elemento de lista en Android, se le da su índice. Entonces Setno se puede usar aquí.
TheRealChx101
¿Cómo puedo abordar esto cuando la lista es una lista de objetos
Jvargas
28

También puede hacerlo de esta manera y preservar el orden:

// delete duplicates (if any) from 'myArrayList'
myArrayList = new ArrayList<String>(new LinkedHashSet<String>(myArrayList));
Nenad Bulatovic
fuente
Creo que esta es la mejor manera de eliminar duplicados en una ArrayList. Definitivamente recomendado. Gracias @Nenad por la respuesta.
ByWaleed
25

Las secuencias Java 8 proporcionan una forma muy simple de eliminar elementos duplicados de una lista. Usando el método distinto. Si tenemos una lista de ciudades y queremos eliminar duplicados de esa lista, se puede hacer en una sola línea:

 List<String> cityList = new ArrayList<>();
 cityList.add("Delhi");
 cityList.add("Mumbai");
 cityList.add("Bangalore");
 cityList.add("Chennai");
 cityList.add("Kolkata");
 cityList.add("Mumbai");

 cityList = cityList.stream().distinct().collect(Collectors.toList());

Cómo eliminar elementos duplicados de una lista de arrays

infoj
fuente
25

Aquí hay una manera que no afecta el orden de su lista:

ArrayList l1 = new ArrayList();
ArrayList l2 = new ArrayList();

Iterator iterator = l1.iterator();

while (iterator.hasNext()) {
    YourClass o = (YourClass) iterator.next();
    if(!l2.contains(o)) l2.add(o);
}

l1 es la lista original, y l2 es la lista sin elementos repetidos (asegúrese de que YourClass tenga el método de igualdad de acuerdo con lo que desea representar para la igualdad)

stbn
fuente
Esta respuesta carece de dos cosas: 1) No usa genéricos, pero tipos sin procesar ( ArrayList<T>deben usarse en lugar de ArrayList) 2) La creación explícita de iteradores puede evitarse usando a for (T current : l1) { ... }. Incluso si quisieras usar Iteratorexplícitamente, iteradorestá mal escrito.
RAnders00
44
Y esta implementación se ejecuta en tiempo cuadrático, en comparación con la implementación del conjunto de hash vinculado que se ejecuta en tiempo lineal. (es decir, esto toma 10 veces más tiempo en una lista con 10 elementos, 10,000 veces más tiempo en una lista con 10,000 elementos. La implementación de JDK 6 para ArrayList.contains , JDK8 impl es lo mismo).
Patrick M
21

Es posible eliminar duplicados de la lista de arrays sin usar HashSet o una lista de arrays más .

Prueba este código ...

    ArrayList<String> lst = new ArrayList<String>();
    lst.add("ABC");
    lst.add("ABC");
    lst.add("ABCD");
    lst.add("ABCD");
    lst.add("ABCE");

    System.out.println("Duplicates List "+lst);

    Object[] st = lst.toArray();
      for (Object s : st) {
        if (lst.indexOf(s) != lst.lastIndexOf(s)) {
            lst.remove(lst.lastIndexOf(s));
         }
      }

    System.out.println("Distinct List "+lst);

La salida es

Duplicates List [ABC, ABC, ABCD, ABCD, ABCE]
Distinct List [ABC, ABCD, ABCE]
CarlJohn
fuente
Es lento y puede obtener una ConcurrentModificationException.
maaartinus
@maaartinus ¿Has probado ese código? No producirá ninguna excepción. También es bastante rápido. Probé el código antes de publicar.
CarlJohn
44
Tienes razón, no lo hace mientras iteras la matriz en lugar de la lista. Sin embargo, es lento como el infierno. Pruébalo con unos pocos millones de elementos. Compáralo con ImmutableSet.copyOf(lst).toList().
maaartinus
responde la pregunta que me hicieron en la entrevista. Cómo eliminar valores repetidos de una ArrayList sin usar Sets. Gracias
Aniket Paul
Internamente, indexOfitera lstutilizando un bucle for.
Patrick M
21

También hay ImmutableSetde guayaba como opción ( aquí está la documentación):

ImmutableSet.copyOf(list);
Timofey Gorshkov
fuente
1
Tenga en cuenta que hay un ImmutableSet.asList()método, devolviendo un ImmutableList, si lo necesita de nuevo como a List.
Andy Turner
19

Esto puede resolver el problema:

private List<SomeClass> clearListFromDuplicateFirstName(List<SomeClass> list1) {

     Map<String, SomeClass> cleanMap = new LinkedHashMap<String, SomeClass>();
     for (int i = 0; i < list1.size(); i++) {
         cleanMap.put(list1.get(i).getFirstName(), list1.get(i));
     }
     List<SomeClass> list = new ArrayList<SomeClass>(cleanMap.values());
     return list;
}
usuario2868724
fuente
1
Me gustó más esta solución.
Tushar Gogna
12

Probablemente un poco exagerado, pero disfruto este tipo de problema aislado. :)

Este código utiliza un conjunto temporal (para la verificación de unicidad) pero elimina elementos directamente dentro de la lista original. Dado que la eliminación de elementos dentro de una ArrayList puede inducir una gran cantidad de copia de matriz, se evita el método remove (int).

public static <T> void removeDuplicates(ArrayList<T> list) {
    int size = list.size();
    int out = 0;
    {
        final Set<T> encountered = new HashSet<T>();
        for (int in = 0; in < size; in++) {
            final T t = list.get(in);
            final boolean first = encountered.add(t);
            if (first) {
                list.set(out++, t);
            }
        }
    }
    while (out < size) {
        list.remove(--size);
    }
}

Mientras estamos en ello, aquí hay una versión para LinkedList (¡mucho mejor!):

public static <T> void removeDuplicates(LinkedList<T> list) {
    final Set<T> encountered = new HashSet<T>();
    for (Iterator<T> iter = list.iterator(); iter.hasNext(); ) {
        final T t = iter.next();
        final boolean first = encountered.add(t);
        if (!first) {
            iter.remove();
        }
    }
}

Use la interfaz de marcador para presentar una solución unificada para List:

public static <T> void removeDuplicates(List<T> list) {
    if (list instanceof RandomAccess) {
        // use first version here
    } else {
        // use other version here
    }
}

EDITAR: Supongo que las cosas genéricas realmente no agregan ningún valor aquí ... Oh, bueno. :)

voleo
fuente
1
¿Por qué usar ArrayList en el parámetro? ¿Por qué no solo List? ¿Eso no funcionará?
Shervin Asgari
Una Lista funcionará absolutamente como parámetro dentro del primer método listado. Sin embargo, el método está optimizado para su uso con una lista de acceso aleatorio como ArrayList, por lo que si se pasa una LinkedList en su lugar obtendrá un bajo rendimiento. Por ejemplo, configurar el elemento n: th en una LinkedList toma tiempo O (n), mientras que configurar el elemento n: th en una lista de acceso aleatorio (como ArrayList) toma tiempo O (1). De nuevo, sin embargo, esto probablemente sea exagerado ... Si necesita este tipo de código especializado, es de esperar que se encuentre en una situación aislada.
volley
10
public static void main(String[] args){
    ArrayList<Object> al = new ArrayList<Object>();
    al.add("abc");
    al.add('a');
    al.add('b');
    al.add('a');
    al.add("abc");
    al.add(10.3);
    al.add('c');
    al.add(10);
    al.add("abc");
    al.add(10);
    System.out.println("Before Duplicate Remove:"+al);
    for(int i=0;i<al.size();i++){
        for(int j=i+1;j<al.size();j++){
            if(al.get(i).equals(al.get(j))){
                al.remove(j);
                j--;
            }
        }
    }
    System.out.println("After Removing duplicate:"+al);
}
Manash Ranjan Dakua
fuente
Esta implementación no devuelve ningún elemento en la lista debido a la última
j--
1
Este trabajo de implementación está muy bien. No hay ningún problema detrás de esto y para esta tarea solo uso una lista de matrices. Por lo tanto, esta respuesta es completamente buena. Manash
Manash Ranjan Dakua
5

Si está dispuesto a usar una biblioteca de terceros, puede usar el método distinct()en Eclipse Collections (anteriormente GS Collections).

ListIterable<Integer> integers = FastList.newListWith(1, 3, 1, 2, 2, 1);
Assert.assertEquals(
    FastList.newListWith(1, 3, 2),
    integers.distinct());

La ventaja de usar en distinct()lugar de convertir a un Conjunto y luego volver a una Lista es que distinct()conserva el orden de la Lista original, conservando la primera aparición de cada elemento. Se implementa mediante el uso de un conjunto y una lista.

MutableSet<T> seenSoFar = UnifiedSet.newSet();
int size = list.size();
for (int i = 0; i < size; i++)
{
    T item = list.get(i);
    if (seenSoFar.add(item))
    {
        targetCollection.add(item);
    }
}
return targetCollection;

Si no puede convertir su Lista original en un tipo de Colecciones de Eclipse, puede usar ListAdapter para obtener la misma API.

MutableList<Integer> distinct = ListAdapter.adapt(integers).distinct();

Nota: Soy un committer para Eclipse Collections.

Craig P. Motlin
fuente
3

Estas tres líneas de código pueden eliminar el elemento duplicado de ArrayList o de cualquier colección.

List<Entity> entities = repository.findByUserId(userId);

Set<Entity> s = new LinkedHashSet<Entity>(entities);
entities.clear();
entities.addAll(s);
M Kaweepatt Churcharoen
fuente
2

Cuando esté completando ArrayList, use una condición para cada elemento. Por ejemplo:

    ArrayList< Integer > al = new ArrayList< Integer >(); 

    // fill 1 
    for ( int i = 0; i <= 5; i++ ) 
        if ( !al.contains( i ) ) 
            al.add( i ); 

    // fill 2 
    for (int i = 0; i <= 10; i++ ) 
        if ( !al.contains( i ) ) 
            al.add( i ); 

    for( Integer i: al )
    {
        System.out.print( i + " ");     
    }

Obtendremos una matriz {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

HarpyWar
fuente
2

Si desea conservar su pedido, lo mejor es utilizar LinkedHashSet . Porque si desea pasar esta lista a una consulta de inserción al iterarla, el orden se conservará.

Prueba esto

LinkedHashSet link=new LinkedHashSet();
List listOfValues=new ArrayList();
listOfValues.add(link);

Esta conversión será muy útil cuando desee devolver una Lista pero no un Conjunto.

RAM
fuente
2

Código:

List<String> duplicatList = new ArrayList<String>();
duplicatList = Arrays.asList("AA","BB","CC","DD","DD","EE","AA","FF");
//above AA and DD are duplicate
Set<String> uniqueList = new HashSet<String>(duplicatList);
duplicatList = new ArrayList<String>(uniqueList); //let GC will doing free memory
System.out.println("Removed Duplicate : "+duplicatList);

Nota: Definitivamente, habrá sobrecarga de memoria.

sambhu
fuente
2
ArrayList<String> city=new ArrayList<String>();
city.add("rajkot");
city.add("gondal");
city.add("rajkot");
city.add("gova");
city.add("baroda");
city.add("morbi");
city.add("gova");

HashSet<String> hashSet = new HashSet<String>();
hashSet.addAll(city);
city.clear();
city.addAll(hashSet);
Toast.makeText(getActivity(),"" + city.toString(),Toast.LENGTH_SHORT).show();
Hardip
fuente
1

LinkedHashSet hará el truco.

String[] arr2 = {"5","1","2","3","3","4","1","2"};
Set<String> set = new LinkedHashSet<String>(Arrays.asList(arr2));
for(String s1 : set)
    System.out.println(s1);

System.out.println( "------------------------" );
String[] arr3 = set.toArray(new String[0]);
for(int i = 0; i < arr3.length; i++)
     System.out.println(arr3[i].toString());

// salida: 5,1,2,3,4

usuario1912383
fuente
1
        List<String> result = new ArrayList<String>();
        Set<String> set = new LinkedHashSet<String>();
        String s = "ravi is a good!boy. But ravi is very nasty fellow.";
        StringTokenizer st = new StringTokenizer(s, " ,. ,!");
        while (st.hasMoreTokens()) {
            result.add(st.nextToken());
        }
         System.out.println(result);
         set.addAll(result);
        result.clear();
        result.addAll(set);
        System.out.println(result);

output:
[ravi, is, a, good, boy, But, ravi, is, very, nasty, fellow]
[ravi, is, a, good, boy, But, very, nasty, fellow]
siva
fuente
1

Esto se usa para su lista de objetos personalizados

   public List<Contact> removeDuplicates(List<Contact> list) {
    // Set set1 = new LinkedHashSet(list);
    Set set = new TreeSet(new Comparator() {

        @Override
        public int compare(Object o1, Object o2) {
            if (((Contact) o1).getId().equalsIgnoreCase(((Contact) o2).getId()) /*&&
                    ((Contact)o1).getName().equalsIgnoreCase(((Contact)o2).getName())*/) {
                return 0;
            }
            return 1;
        }
    });
    set.addAll(list);

    final List newList = new ArrayList(set);
    return newList;
}
Gujjula Ramesh Reddy
fuente
1

puede usar el bucle anidado de la siguiente manera:

ArrayList<Class1> l1 = new ArrayList<Class1>();
ArrayList<Class1> l2 = new ArrayList<Class1>();

        Iterator iterator1 = l1.iterator();
        boolean repeated = false;

        while (iterator1.hasNext())
        {
            Class1 c1 = (Class1) iterator1.next();
            for (Class1 _c: l2) {
                if(_c.getId() == c1.getId())
                    repeated = true;
            }
            if(!repeated)
                l2.add(c1);
        }
HamidReza
fuente
1

Como se dijo anteriormente, debe usar una clase que implemente la interfaz Set en lugar de List para asegurarse de la unicidad de los elementos. Si tiene que mantener el orden de los elementos, se puede usar la interfaz SortedSet; la clase TreeSet implementa esa interfaz.

Vinze
fuente
1

Si está utilizando el tipo de modelo Lista <T> / ArrayList <T>. Espero que sea de ayuda.

Aquí está mi código sin usar ninguna otra estructura de datos como set o hashmap

for (int i = 0; i < Models.size(); i++){
for (int j = i + 1; j < Models.size(); j++) {       
 if (Models.get(i).getName().equals(Models.get(j).getName())) {    
 Models.remove(j);
   j--;
  }
 }
}
Saurabh Gaddelpalliwar
fuente
0
for(int a=0;a<myArray.size();a++){
        for(int b=a+1;b<myArray.size();b++){
            if(myArray.get(a).equalsIgnoreCase(myArray.get(b))){
                myArray.remove(b); 
                dups++;
                b--;
            }
        }
}
Ghyour
fuente
0
import java.util.*;
class RemoveDupFrmString
{
    public static void main(String[] args)
    {

        String s="appsc";

        Set<Character> unique = new LinkedHashSet<Character> ();

        for(char c : s.toCharArray()) {

            System.out.println(unique.add(c));
        }
        for(char dis:unique){
            System.out.println(dis);
        }


    }
}
reddy
fuente
0
public Set<Object> findDuplicates(List<Object> list) {
        Set<Object> items = new HashSet<Object>();
        Set<Object> duplicates = new HashSet<Object>();
        for (Object item : list) {
            if (items.contains(item)) {
                duplicates.add(item);
                } else { 
                    items.add(item);
                    } 
            } 
        return duplicates;
        }
Harsha
fuente
0
    ArrayList<String> list = new ArrayList<String>();
    HashSet<String> unique = new LinkedHashSet<String>();
    HashSet<String> dup = new LinkedHashSet<String>();
    boolean b = false;
    list.add("Hello");
    list.add("Hello");
    list.add("how");
    list.add("are");
    list.add("u");
    list.add("u");

    for(Iterator iterator= list.iterator();iterator.hasNext();)
    {
        String value = (String)iterator.next();
        System.out.println(value);

        if(b==unique.add(value))
            dup.add(value);
        else
            unique.add(value);


    }
    System.out.println(unique);
    System.out.println(dup);
SparkOn
fuente
0

Si desea eliminar duplicados de ArrayList significa encontrar la siguiente lógica,

public static Object[] removeDuplicate(Object[] inputArray)
{
    long startTime = System.nanoTime();
    int totalSize = inputArray.length;
    Object[] resultArray = new Object[totalSize];
    int newSize = 0;
    for(int i=0; i<totalSize; i++)
    {
        Object value = inputArray[i];
        if(value == null)
        {
            continue;
        }

        for(int j=i+1; j<totalSize; j++)
        {
            if(value.equals(inputArray[j]))
            {
                inputArray[j] = null;
            }
        }
        resultArray[newSize++] = value;
    }

    long endTime = System.nanoTime()-startTime;
    System.out.println("Total Time-B:"+endTime);
    return resultArray;
}
Thananjayan N
fuente
1
¿Por qué publicar una solución cuadrática a una pregunta que ya tiene soluciones lineales y log-lineales de 2 años, que también son más simples?
abarnert