2008-12-10 18 views
15

Tengo una matriz de objetos que necesitan eliminar o filtrar los duplicados. Iba a sobrescribir igual a & hachCode en los elementos del objeto, y luego pegarlos en un conjunto ... pero pensé que debería al menos sondear stackoverflow para ver si había otra forma, tal vez algún método inteligente de alguna otra API ?¿Cuál es la mejor manera de eliminar duplicados en una matriz en Java?

+1

Por qué colocarse en este lugar? ¿Por qué no prevenir los duplicados en primer lugar? – LeppyR64

+4

Haga una pregunta sobre eliminar duplicados ... obtenga un montón de respuestas duplicadas. ¡La ironía! – erickson

+1

lol @ erickson, ¡tan cierto! – Brabster

Respuesta

19

Estoy de acuerdo con su enfoque para anular hashCode() y equals() y usar algo que implemente Set.

Hacerlo también deja absolutamente en claro para cualquier otro desarrollador que se requiere la característica de no duplicar.

Otra razón - que llegar a elegir una implementación que se adapte a sus necesidades mejor ahora:

y usted no tiene que cambiar su código para cambiar la implementación en el futuro.

0

A Set es definitivamente su mejor apuesta. La única manera de eliminar elementos de una matriz (sin crear uno nuevo) es anularlos, y luego terminará con muchos controles nulos más adelante.

3

Reemplazando equals y hashCode y creando un conjunto fue mi primer pensamiento también. Es una buena práctica tener alguna versión anulada de estos métodos de todos modos en su jerarquía de herencia.

Yo creo que si se utiliza un LinkedHashSet incluso se va a preservar el orden de los elementos únicos ...

+0

Sí, 'LinkedHashSet' mantendrá el orden de inserción. –

+0

No es una buena práctica anular equals y hashCode "de todos modos", especialmente en cualquier clase que se sitúe en una jerarquía de herencia. Vea Java efectivo (Bloch) para más. – McDowell

+0

McDowell, me wa no muy claro - que quería decir que no debe haber una versión sustituida * * algún lugar en la jerarquía de herencia, y he modificado la respuesta a reflejar eso. No tengo una copia de Java efectivo: ¿es esto a lo que está apuntando Bloch? –

8

encontré esto en la web

Aquí son dos métodos que le permiten eliminar los duplicados en una ArrayList. removeDuplicate no mantiene el orden donde removeDuplicateWithOrder mantiene el orden con algunos gastos generales de rendimiento.

  1. El Método removeDuplicate:

    /** List order not maintained **/ 
    public static void removeDuplicate(ArrayList arlList) 
    { 
    HashSet h = new HashSet(arlList); 
    arlList.clear(); 
    arlList.addAll(h); 
    } 
    
  2. El Método removeDuplicateWithOrder:

    /** List order maintained **/ 
    public static void removeDuplicateWithOrder(ArrayList arlList) 
    { 
        Set set = new HashSet(); 
        List newList = new ArrayList(); 
        for (Iterator iter = arlList.iterator(); iter.hasNext();) { 
         Object element = iter.next(); 
         if (set.add(element)) 
         newList.add(element); 
        } 
        arlList.clear(); 
        arlList.addAll(newList); 
    } 
    
+0

Buena respuesta, pero su segundo ejemplo no está en un bloque de formato de código – TravisO

+0

gracias a Ken G ...Lo intenté un par de veces pero no pude solucionar el segundo código de blog –

+1

LinkedHashSet lo mantiene en orden. Eso puede optimizarlo aún más. –

0

Hablando desde un estándar de programación general siempre se puede enumerar el doble de las colecciones entonces el comparar la fuente y objetivo

Y si su enumeración interior siempre se inicia después de una entrada de la fuente, es bastante eficiente (pseudo código para seguir)

foreach (array as source) 
{ 
    // keep track where we are in the array 
    place++; 
    // loop the array starting at the entry AFTER the current one we are comparing to 
    for (i=place+1; i < max(array); i++) 
    { 
     if (source === array[place]) 
     { 
      destroy(array[i]); 
     } 
    } 
} 

Se podría añadir sin duda un descanso; declaración después de la destrucción, pero luego solo descubres el primer duplicado, pero si eso es todo lo que tendrás, entonces sería una buena optimización pequeña.

1

me gustaría reiterar el argumento de Jason en los comentarios:

Por qué coloque a sí mismo en ese punto en absoluto?

¿Por qué utilizar una matriz de una estructura de datos que no deberían contener duplicados en absoluto?

Use Set o SortedSet (cuando los elementos tienen un orden natural también) en todo momento para contener los elementos. Si necesita mantener el orden de inserción, puede usar el LinkedHashSet como se ha señalado.

Tener a post-proceso de alguna estructura de datos es a menudo un indicio de que debería haber elegido una diferente, para empezar.

+0

Estoy de acuerdo con todos los comentarios sobre las preocupaciones de que la estructura de datos inicial sea una matriz. Intento presionar al desarrollador para que refactorice a un conjunto. ¡Gracias a todos por sus comentarios y sabiduría! – Liggy

1

Por supuesto el post original plantea la pregunta: "¿Cómo se obtiene esa matriz (que puede contener entradas duplicadas) en el primer lugar?"

¿Necesita la matriz (con duplicados) para otros fines, o puede simplemente usar un juego desde el principio?

Alternativamente, si usted necesita saber el número de ocurrencias de cada valor, se puede utilizar un Map<CustomObject, Integer> para rastrear conteos. Además, la definición Google Collections de las clases Multimap puede ser útil.

2

Básicamente, desea una implementación LinkedHashSet<T> que admita la interfaz List<T> para acceso aleatorio. Por lo tanto, esto es lo que necesita:

public class LinkedHashSetList<T> extends LinkedHashSet<T> implements List<T> {

// Implementations for List<T> methods here ...

}

La aplicación de los métodos List<T> podría acceder y manipular el LinkedHashSet<T> subyacente. El truco es tener esta clase se comportan correctamente cuando se intenta añadir duplicados a través de los List<T> añadir métodos (lanzando una excepción o volver a añadir el artículo a un índice diferente sería opciones: que se puede elegir uno de o hacer configurable por los usuarios de la clase).

+0

Esto es lo que sugiero, también. –

1

utilizar una lista toRemove para grabar elemento en la primera vez iterator tropiezo en él, después, cuando se reúnen de nuevo con el elemento registrado, y eliminar el uso de iterator.remove()

 
private void removeDups(List list) { 
     List toRemove = new ArrayList(); 
     for(Iterator it = list.iterator(); it.hasNext();) { 
      Object next = it.next(); 
      if(!toRemove.contains(next)) { 
       toRemove.add(next); 
      } else { 
       it.remove(); 
      } 
     } 
     toremove.clear(); 
    } 

Cuestiones relacionadas