Подтвердить что ты не робот

Удаление объектов из ArrayList в Java

Мне нужно удалить некоторые объекты из ArrayList, если они удовлетворяют условию, и мне интересно, какой способ может быть более эффективным.

Здесь ситуация: у меня есть класс, содержащий ArrayList, содержащий некоторые другие объекты. Я должен перебрать этот ArrayList и удалить все элементы, удовлетворяющие определенному условию. Насколько мне известно, это будут мои варианты удаления:

  • Создайте новый ArrayList и добавьте элементы, которые не соответствуют этому условию. После итерации замените старый аррайалист на новый без элементов.

  • Создайте новый ArrayList и добавьте элементы, соответствующие этому условию. После итерации используйте метод removeAll(), передающий ArrayList с объектами, которые нужно удалить.

Есть ли более эффективный способ удаления объектов из ArrayList?

4b9b3361

Ответ 1

Другой способ: у Iterator есть необязательный метод remove(), который реализуется для ArrayList. Вы можете использовать его во время итерации.

Я не знаю, хотя, какой вариант наиболее эффективен, вы должны его измерить.

starblue прокомментировал, что сложность не очень хорошая, и что true (для removeAll() тоже), потому что ArrayList должен копировать все элементы, если в середине добавлен или удален элемент. Для этих случаев лучше использовать LinkedList. Но, поскольку все мы не знаем ваших реальных случаев использования, лучше всего измерять все варианты, чтобы выбрать наилучшее решение.

Ответ 2

Вы можете повторять и удалять, когда вы проходите через ArrayList. Это имеет то преимущество, что последующие элементы не нуждаются в переключении и легче программировать, чем перемещение вперед.

Ответ 3

Большинство исполнителей, я думаю, будут использовать метод listIterator и выполнить обратную итерацию:

for (ListIterator<E> iter = list.listIterator(list.size()); iter.hasPrevious();){
    if (weWantToDelete(iter.previous()))  iter.remove();
}

Изменить:. Значительно позже можно было бы добавить способ удаления 8 элементов Java 8 из (или любой коллекции!) с использованием ссылки лямбда или метода. На месте filter для коллекций, если хотите:

list.removeIf(e -> e.isBad() && e.shouldGoAway());

Это, вероятно, лучший способ очистки коллекции. Так как он использует внутреннюю итерацию, реализация коллекции может принимать быстрые клавиши, чтобы сделать это как можно быстрее (для ArrayList s, это может свести к минимуму необходимое количество копий).

Ответ 4

Очевидно, что из двух методов, которые вы упомянули, номер 1 более эффективен, поскольку он должен проходить один раз только один раз, а с номером 2 список должен пройти два раза (сначала для поиска элементов для удаления, и их удалить их).

Фактически, удаление списка элементов из другого списка, скорее всего, является алгоритмом, который хуже, чем O (n), поэтому метод 2 еще хуже.

Метод итератора:

List data = ...;

for (Iterator i = data.iterator(); i.hasNext(); ) {
    Object element = i.next();

    if (!(...)) {
        i.remove();
    }
}

Ответ 5

Во-первых, я бы удостоверился, что это действительно узкое место в производительности, иначе я бы пошел с самым чистым и выразительным решением.

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

Ответ 6

Если вы не уверены, что проблема, с которой вы столкнулись, действительно является узким местом, я бы пошел на удобочитаемый

public ArrayList filterThings() {

    ArrayList pileOfThings;
    ArrayList filteredPileOfThings = new ArrayList();

    for (Thing thingy : pileOfThings) {
        if (thingy.property != 1) {
            filteredPileOfThings.add(thingy);
        }            
    }
    return filteredPileOfThings;
}

Ответ 7

Существует скрытая стоимость удаления элементов из ArrayList. Каждый раз, когда вы удаляете элемент, вам нужно переместить элементы, чтобы заполнить "отверстие". В среднем это займет N / 2 назначения для списка с N элементами.

Таким образом, удаление M элементов из элемента N ArrayList в среднем равно O(M * N). Решение O (N) предполагает создание нового списка. Например.

List data = ...;
List newData = new ArrayList(data.size()); 

for (Iterator i = data.iterator(); i.hasNext(); ) {
    Object element = i.next();

    if ((...)) {
        newData.add(element);
    }
}

Если N велико, я предполагаю, что этот подход будет быстрее, чем подход remove для значений M, равный 3 или 4.

Но важно создать newList достаточно большой, чтобы удерживать все элементы в list, чтобы избежать копирования массива поддержки при его расширении.

Ответ 8

int sizepuede= listaoptionVO.size();
for (int i = 0; i < sizepuede; i++) {
    if(listaoptionVO.get(i).getDescripcionRuc()==null){
        listaoptionVO.remove(listaoptionVO.get(i));
        i--;
        sizepuede--;
     }
}

edit: добавлен отступ

Ответ 9

Может быть Iterator s remove() метод? В классах коллекции по умолчанию JDKs должны быть все создатели-итераторы, которые поддерживают этот метод.

Ответ 10

Я нашел альтернативное более быстрое решение:

  int j = 0;
  for (Iterator i = list.listIterator(); i.hasNext(); ) {
    j++;

    if (campo.getNome().equals(key)) {
       i.remove();
       i = list.listIterator(j);
    }
  }

Ответ 11

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

Iterator itr = list.iterator();
String strElement = "";
while(itr.hasNext()){

  strElement = (String)itr.next();
  if(strElement.equals("2"))
  {
    itr.remove();
  }

Ответ 12

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

Точно, что я делал:

ArrayList < HashMap < String , String >> results; // This has been filled with a whole bunch of results

ArrayList < HashMap < String, String → discard = findResultsToDiscard (результаты);

results.removeall(отбрасывания);

Однако метод удаления всего метода занимал более 6 секунд (не включая метод получения результатов отбрасывания), чтобы удалить приблизительно 800 результатов из массива 2000 (ish).

Я попробовал метод итератора, предложенный gustafc и другими на этом посту.

Это немного ускорило операцию (примерно до 4 секунд), однако это было еще недостаточно. Поэтому я попробовал что-то рискованное...

 ArrayList < HashMap < String, String>> results;

  List < Integer > noIndex = getTheDiscardedIndexs(results);

for (int j = noIndex.size()-1; j >= 0; j-- ){
    results.remove(noIndex.get(j).intValue());
}

в то время как getTheDiscardedIndexs сохраняют массив индекса, а не массив HashMaps. Это, как оказалось, ускоряет удаление объектов намного быстрее (примерно 0,1 секунды) и будет иметь большую эффективность памяти, так как нам не нужно создавать большой массив результатов для удаления.

Надеюсь, это поможет кому-то.

Ответ 13

Я хорошо разбираюсь в Mnemmenth recommentation.
Только одно предупреждение,

 ConcurrentModificationException

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