2010-09-22 8 views
8

Tengo la siguiente lógica para eliminar usuarios inactivos en el sistema, ya que no podemos eliminar una fila mientras iteramos en la lista. ¿Hay una mejor manera de manejar esto?Cuál es la mejor manera de eliminar objetos de una lista

List<User> users = new ArrayList<User>(); 
List<User> removeUsers = new ArrayList<User>(); 

for (User user : users) { 
    if (!user.isActive()) { 
     removeUsers.add(user); 
    } 
} 

users.removeAll(removeUsers); 

Respuesta

8

Esa es una forma perfectamente posible hacerlo en mi humilde opinión.

Otras formas en las que podría hacerlo, utilice la indexación y elimine a medida que avanza en reversa.

for (int i = users.size()-1; i >= 0; i--) 
{ 
    if (!users.get(i).isActive()) 
    { 
     users.remove(i); 
    } 
} 

O crear una nueva lista de los elementos que se deben llevar y reemplazarla con la lista de edad.

List<User> newUsers = new ArrayList<User>(); 
for (User user : users) 
{ 
    if (user.isActive()) 
    { 
     newUsers.add(user); 
    } 
} 
users = newUsers; 

No se me ocurren otros en este momento.

+0

'Iterator.remove()' funciona bien también como [maxkar] (http: // stackoverflow.com/questions/3767087/what-is-the-best-way-to-remove-objects-from-a-list/3767175 # 3767175) señalado. –

+2

-1 Demasiado desorden. Iterando en reversa con un índice? – abyx

+0

@abyx: ¿demasiado desorden? Discutible. No lo hace menos válido. Claro que podría haber agregado usando 'Iterator.remove()' a mi respuesta que parece más limpia, estoy de acuerdo. Pero opté por referirme a la respuesta de otra persona (igualmente buena) en su lugar. –

1

Se podría hacer:

for (int i = users.size()-1; i >= 0; i--) { 
    if (!users.get(i).isActive()) { 
    users.remove(i); 
    } 
} 
4

¿Qué tal si usamos un poco de magia Guava?

List<User> users = new ArrayList<User>(); 
Iterables.removeIf(users, new Predicate<User>() { 

@Override 
public boolean apply(User user) { 
    return !user.isActive(); 
} 
}); 

Si utiliza el predicado en varios lugar que podría incluso crear una clase llamada aquí para allá y hacer que el código aún mejor:

private static final class IsNotActiveUserPredicate implements Predicate<User> { 
@Override 
public boolean apply(User user) { 
    return !user.isActive(); 
} 
} 

List<User> users = new ArrayList<User>(); 
Iterables.removeIf(users, new IsNotActiveUserPredicate()); 
+0

+1 para magia de guayaba – chedine

13

Si utiliza ArrayList, la mejor manera es la variante de Jeff M. También puede usar su variante, pero debería considerar usar Set (HashSet o IdentityHashSet) en lugar de ArrayList para removeUser. Para una gran cantidad de datos, tendrá un mejor rendimiento.

Pero para LinkedList mejor manera habrá de utilizar el método Iterator.remove:

for (Iterator<User> it = users.iterator(); it.hasNext();) 
    if (it.next().isActive()) 
     it.remove(); 
+0

Ah, sí, Iterator.remove() también funciona para ArrayLists. Esto también sería muy limpio. –

3

La forma Gosling pretende que hagamos se está utilizando Iterator.remove:

Iterator<User> it = users.iterator(); 
while (it.hasNext()) { 
    if (! it.next().isActive()) { 
     it.remove(); 
    } 
} 

Esto podría no ser la mejor desde una perspectiva de rendimiento si está usando ArrayList, pero, de nuevo, parece que podría considerar cambiar a LinkedList.

En cualquier caso, esta es la forma de eliminar elementos de una colección mientras se itera sobre ella.

+0

El iterador no es a prueba de fallos. La modificación estructural de una estructura de datos no es buena. –

+0

@Suresh Otra pregunta, ¿qué quiere decir con "iterator is not fail safe"? – zengr

+1

@Zengr en iteraciones u no debe eliminar anyelements, de esa manera la hasNext y el próximo se producirá un error, porque u havent notificada a la clase de iterador en la estructura de datos de modificación (es decir, u han eliminado un elemento poco, pero u ejecutarse en un objeto iterador más.) –

0

Aquí es otra versión de guayaba usando Collections2.filter:

final List<User> activeUsers = 
    Lists.newArrayList(Collections2.filter(userList, new Predicate<User>(){ 

     @Override 
     public boolean apply(final User input){ 
      return input.isActive(); 
     } 
    })); 
0

Aquí hay otro enfoque que es bastante eficiente, con listas basadas matriz. Esto se debe a que no necesita copiar toda la cola con cada eliminación. Utiliza 2 pasos: Primero, todos los elementos que se deben conservar se copian en su posición final al comienzo de la lista y luego se eliminan todos los elementos restantes al final de la lista.

public static void removeInactiveUsers(ArrayList<User> users) 
{ 

    int j = 0, len = users.size(); 
    for(int i = 0; i < len; ++i) 
    { 
     User user = user.get(i); 
     if(user.isActive()) 
     { 
      if(i != j) 
       users.set(j, user); 
      ++j; 
     } 
    } 
    users.removeRange(j, len); 
} 
0

Si desea eliminar un objeto como el objeto actual o el objeto seleccionado, puede seguir los pasos a continuación.

Object currentObject = null; 
    for (User user : users) 
    { 
     if (user.isActive()) 
     { 
      currentObject = user ; 
     } 
    } 

    if(currentObject != null) { 
    users.remove(currentObject); 
    } 
Cuestiones relacionadas