2010-09-22 11 views
8

Mam następującą logikę, aby usunąć nieaktywnych użytkowników w systemie, ponieważ nie możemy usunąć wiersza podczas iteracji na liście. Czy jest lepszy sposób to obsłużyć?Jaki jest najlepszy sposób usuwania obiektów z listy

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

Odpowiedz

8

to jest idealnie czysty sposób to zrobić IMHO.

Inne sposoby, w jakie mogę to zrobić, użyj indeksowania i usuń podczas przeglądania w odwrotnej kolejności.

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

Lub utwórz nową listę przedmiotów, które mają być przechowywane, i zastąp ją starą listą.

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

Nie mogę teraz myśleć o innych.

+0

'Iterator.remove()' działa również jako [maxkar] (http: // stackoverflow.com/questions/3767087/what-is-the-best-to-remove-to-remove-objects-from-a-list/3767175 # 3767175) wskazał. –

+2

-1 Za dużo bałaganu. Iteracja odwrotnie z indeksem? – abyx

+0

@abyx: Za dużo bałaganu? Sporny. Nie czyni go mniej ważnym. Pewnie mogłem dodać używając 'Iterator.remove()' do mojej odpowiedzi, która wygląda czystsza, zgadzam się. Ale zamiast tego zdecydowałem się na odpowiedź innej osoby (równie dobrze). –

1

Można zrobić:

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

Co powiesz na używanie magii Guava?

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

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

Jeśli używasz orzecznika w kilku miejscu można nawet utworzyć nazwie klasy fro nim i uczynić swój kod nawet lepiej:

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 dla guawy magicznej – chedine

13

Jeśli używasz ArrayList, najlepszym sposobem jest wariant Jeff M. Możesz także użyć swojego wariantu, ale powinieneś rozważyć użycie Set (HashSet lub IdentityHashSet) w bazie ArrayList dla removeUser. W przypadku dużej ilości danych uzyska lepszą wydajność.

Ale dla LinkedList najlepszym sposobem będzie użycie metody Iterator.remove:

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

O tak, Iterator.remove() działa również dla ArrayLists. To też byłoby bardzo czyste. –

3

Sposób Gosling przeznaczone nam to zrobić jest użycie Iterator.remove:

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

To może nie być najlepszym z perspektywy wydajności, jeśli używasz ArrayList, ale z drugiej strony wydaje się, że warto rozważyć zmianę na LinkedList.

W ten sposób można usunąć elementy z kolekcji podczas iteracji.

+0

iterator nie jest bezpieczny w razie awarii. Strukturalnie modyfikacja danych nie jest dobra. –

+0

@Suresh Kolejne pytanie, co rozumiesz przez "iterator nie jest bezpieczny"? – zengr

+1

@Zengr na iteracji nie należy usuwać żadnych elementów, w ten sposób hasNext i następna zakończy się niepowodzeniem, ponieważ nie trzeba było powiadamiać klasy iteratora o modyfikacji danych (np. Usunąłeś element ostatnio, ale uruchomiłeś go na starszym obiekcie iteratora). –

0

Oto kolejna wersja Guava użyciu 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

Oto inne podejście, które jest dość skuteczny w oparciu o list tablicowych. Dzieje się tak dlatego, że nie trzeba kopiować całego ogona przy każdym usunięciu. Używa dwóch kroków: Najpierw wszystkie elementy, które muszą zostać zachowane, są kopiowane do ostatecznej pozycji na początku listy, a następnie usuwane są wszystkie pozostałe elementy na końcu listy.

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

Jeśli chcesz usunąć dowolny obiekt, taki jak bieżący obiekt lub wybrany obiekt, wykonaj poniższe czynności.

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

    if(currentObject != null) { 
    users.remove(currentObject); 
    } 
Powiązane problemy