2010-09-22 2 views
8

У меня есть следующая логика для удаления неактивных пользователей в системе, поскольку мы не можем удалить строку при повторении в списке. Есть ли лучший способ справиться с этим?Каков наилучший способ удаления объектов из списка

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

ответ

8

Это совершенно прекрасный способ сделать это ИМХО.

Другие способы, которыми я могу это сделать, использовать индексирование и удалять по мере прохождения в обратном порядке.

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

Или создайте новый список предметов для хранения и замените его на старый список.

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

Невозможно думать о каких-либо других на данный момент.

+0

'Iterator.remove()' отлично работает также как [maxkar] (http: // stackoverflow.com/questions/3767087/what-is-the-best-way-to-remove-objects-from-a-list/3767175 # 3767175). –

+2

-1 Слишком много беспорядка. Итерация в обратном направлении с помощью индекса? – abyx

+0

@abyx: Слишком много помех? Спорно. Не делает его менее действительным. Конечно, я мог бы добавить с помощью 'Iterator.remove()' мой ответ, который выглядит более чистым, я согласен. Но я предпочел ссылаться на ответ другого человека (в равной степени хорошо). –

1

Вы можете сделать:

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

Как насчет использования некоторых Guava магии?

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

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

При использовании предиката в нескольких месте вы могли бы даже создать именованный класс Фро его и сделать код еще лучше:

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 для магии Гува – chedine

13

Если вы используете ArrayList, лучший способ это вариант Jeff M в. Вы также можете использовать свой вариант, но вам следует рассмотреть возможность использования Set (HashSet или IdentityHashSet) вместо ArrayList для removeUser. Для большого объема данных он будет иметь лучшую производительность.

Но для LinkedList наилучшим образом будет использовать Iterator.remove метод:

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

О, да, Iterator.remove() работает и для ArrayLists. Это было бы очень чисто. –

3

Путь Гослинг предназначен нам сделать это с помощью Iterator.remove:

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

Это не может быть лучшим с точки зрения производительности, если вы используете ArrayList, но опять же, похоже, вы можете рассмотреть возможность изменения на LinkedList.

В любом случае, это способ удаления элементов из коллекции во время итерации по ней.

+0

Итератор не подлежит безопасности. Структурная модификация структуры данных не является хорошей. –

+0

@Suresh Другой вопрос, что вы подразумеваете под «итератором, не подлежит безопасности»? – zengr

+1

@ Zengr на итерациях u не должен удалять какие-либо элементы, таким образом hasNext и next будут терпеть неудачу, потому что u havent был уведомлен классу итератора о модификации datastructure (т. Е. Вы удалили элемент недавно, но u запустили на более старый объект итератора). –

0

Вот еще гуавы версии с помощью 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

Вот другой подход, который является довольно эффективным со списками на основе массивов. Это связано с тем, что при каждом удалении не нужно копировать весь хвост. Он использует 2 шага: сначала все элементы, которые необходимо сохранить, копируются в их конечное положение в начале списка, а затем все остальные элементы в конце списка удаляются.

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

Если вы хотите удалить любой объект, например текущий объект или выбранный объект, вы можете следовать ниже.

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

    if(currentObject != null) { 
    users.remove(currentObject); 
    } 
Смежные вопросы