2010-12-01 19 views
6

Deseo buscar a través de un ArrayLst y eliminar las entradas que sean iguales.Modificar una lista de arreglos en Java

Por ejemplo, si mi lista era: manzana, naranja, plátano, pera, melocotón, naranja,

luego "naranja" se suprimiría (ambas ocurrencias).

Ingenuamente, he intentado:

for(String word : userlist){ 

for(String otherword : userlist){ 

... 
} 
} 

donde escribí cómo .Remove (lastIndexOf (userword)) si es igual a la palabra y sus índices son diferentes.

Esto dio lugar a una excepción tras otra, y rápidamente me di cuenta de que estaba manipulando una lista mientras la repetía, lo que hacía que todo saliera mal.

Así que decidimos hacer una copia de la lista

ArrayList<String> copylist = userlist; 

for(String word : copylist){ 

    for(String otherword : copylist){ 

    if(word.equalsIgnoreCase(otherword) 
      && copylist.lastIndexOf(word)!=copylist.lastIndexOf(otherword)){ 

userlist.remove(userlist.lastIndexOf(word)); 
userlist.remove(userlist.lastIndexOf(otherword)); 
    } 

    } 
    } 

así que he intentado esto, y tenía problemas similares. Notablemente ConcurrentModificationException. Después de ajustarlo no puedo entenderlo, lo que en mi cabeza debería ser un proceso bastante fácil, para trabajar en Java. Por favor ayuda.

Respuesta

10

Actualmente no estás haciendo una copia de la lista. Estás declarando una nueva variable que tiene una referencia a la misma lista. Para hacer una copia de la lista, utilice:

ArrayList<String> copyList = new ArrayList<String>(userList); 

Sin embargo, me gustaría sugerir un enfoque diferente:

ArrayList<String> wordsToRemove = new ArrayList<String>(); 
Set<String> seenWords = new HashSet<String>(); 

for (String word : userList) 
{ 
    if (!seenWords.add(word)) 
    { 
     wordsToRemove.add(word); 
    } 
} 

for (String word : wordsToRemove) 
{ 
    // Keep removing it until it doesn't exist any more 
    while (userList.remove(word)) {} 
} 

Este no ignoran caso, sin embargo. Para hacer eso, tiene que ser un poco más inteligente:

Set<String> wordsToRemove = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); 
Set<String> seenWords = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); 

for (String word : userList) 
{ 
    if (!seenWords.add(word)) 
    { 
     wordsToRemove.add(word); 
    } 
} 

// Now we know the words we don't want, step through the list again and 
// remove them (case-insensitively, as wordsToRemove is case-insensitive) 
for (Iterator<String> iterator = userList.iterator(); it.hasNext() ;) 
{ 
    if (wordsToRemove.contains(word)) 
    { 
     iterator.remove(); 
    } 
} 
+1

¿Nunca te vas a dormir? :( – musiKk

+4

@musiKk: ver http://meta.stackexchange.com/questions/555/ –

+1

@MusiKk también ver http://meta.stackexchange.com/questions/9134/jon-skeet-facts –

1
ArrayList<String> copylist = userlist; 

Esta línea asigna la lista de usuarios referencia a la lista de copia y no crea nuevo ArrayList. Apunta a la misma lista de arrays. Para hacer una nueva lista, la manera simple es crear una nueva lista y seguir agregando elementos en esta nueva lista después de verificar si el elemento ya está presente en la nueva lista o no.

ArrayList<String> newList = new ArrayList<String>(); 

foreach(String item in userList) { 
    if(newList.contains(item)==false) 
    { 
      newList.add(item); 
    } 
} 
+0

Eso terminará con una lista sin duplicados, pero todavía contiene * una * instancia de "naranja", por ejemplo. –

+0

'foreach (elemento String en userList)' esto no es Java. Te refieres a 'for (String item: userList)' –

+0

@ S.P.Floyd, lo siento por foreach. Salí de Java hace un año ... ahora estoy trabajando en C# y estoy acostumbrado a foreach ... – Shekhar

1

Es un problema bien conocido: no se puede modificar el contenedor iterado. El truco para resolver es el uso del método remove del iterador:

Iterator<String> tblIter = array.iterator(); 
    while (tblIter.hasNext()) { 
     String entry = tblIter.next(); 
     if(entry.equals(.....)) 
     { 
      ... 
      tblIter.remove(); 
     } 
    } 
+0

Pero recuerda que ambas instancias deben ser eliminadas. No estoy seguro de que esto funcione. Gracias por la respuesta, lo intentaré. –

2

Si desea eliminar el elemento durante la iteración a través de la colección que ha de usar Iterator y Iterator.remove()

pero me gustaría para sugerirle una solución más fácil: ponga su lista en conjunto. Se elimina automáticamente los duplicados:

List<String> mylist = new ArrayList<String>(); 
// some initialization: there are duplicates 

Set<String> myset = new HashSet<String>(mylist); // no duplicates here. 

Puede seguir utilizando conjunto, ya que es recogida y se puede iterar sobre ella.Pero si necesita acceso aleatorio lista crea de nuevo:

newlist = new ArrayList<String>(myset); 

Los elementos de pedido en conjunto será "al azar" como resultado de hash. Si desea conservar el orden original, utilice LinkedHashSet en lugar de HashSet.

+0

Eso terminará con una instancia de "naranja" en lugar de eliminar ambas. La idea es eliminar * todas * copias de cualquier valor que esté duplicado. –

+0

Según tengo entendido, quiere que se eliminen las dos apariciones de un duplicado. Además, puede usar un LinkedHashSet para conservar el orden y reutilizar la lista existente ('list.clear(); list.addAll (set);') – sfussenegger

0

Si usted tiene control sobre cómo se agregan datos, puede crear su propio método de "añadir", algo como esto:

add(element) 
{ 
    if arrayList.contains(element) 
     arrayList.remove(arrayList.indexOf(element)) 

    else 
     arrayList.add(element) 
} 

por otro lado, si usted no tiene control sobre cómo/cuándo los datos se agregan, puede hacer un ciclo y tener una lógica similar a la anterior. Eche un vistazo a here para conocer los métodos apropiados.

+0

¡Gracias! En realidad, tuve oportunidad de probar eso. mi solución actual es muy similar, lo que me parece muy incómodo y puede que no funcione bien cuando agrego más cosas al programa. Quería saber la mejor manera de hacerlo. –

4
import java.util.ArrayList; 
import java.util.HashSet; 
import java.util.List; 
import java.util.Set; 


public class Test { 
    public static void main(String[] args) { 
     List<String> a = new ArrayList<String>(); 
     a.add("apple"); 
     a.add("orange"); 
     a.add("banana"); 
     a.add("pear"); 
     a.add("peach"); 
     a.add("orange"); 
     System.out.println(a); 
     System.out.println(getSingleWordList(a)); 
    } 
    private static List<String> getSingleWordList(List<String> list) 
    { 
     Set<String> uniques = new HashSet<String>(); 
     Set<String> dups = new HashSet<String>(); 

     for (String a : list) 
      if (!uniques.add(a)) 
       dups.add(a); 


     uniques.removeAll(dups); 

     return new ArrayList<String>(uniques); 
    } 
} 

SALIDA

Input = [apple, orange, banana, pear, peach, orange]

Output = [pear, apple, banana, peach]

+3

Eso es bueno, me gusta. Use un 'LinkedHashSet' si se requiere preservación de orden. –

+0

según tengo entendido, quiere que se altere la lista anterior, no una nueva. Por lo tanto, reemplazaría su línea de devolución con 'list.clear(); list.addAll (uniques); ' – sfussenegger

0

Si el objetivo es una colección sin elementos duplicados, analizar si una sería más apropiado que una lista.

Cuestiones relacionadas