Как удалить все нулевые элементы из ArrayList или String Array? - PullRequest
174 голосов
/ 27 января 2011

Я пытаюсь с такой петлей

// ArrayList tourists

for (Tourist t : tourists) {
    if (t != null) {     
        t.setId(idForm); 
    }   
}

Но это нехорошо. Кто-нибудь может предложить мне лучшее решение?


Некоторые полезные ориентиры для принятия лучшего решения:

Пока цикл, для цикла и теста производительности итератора

Ответы [ 17 ]

351 голосов
/ 27 января 2011

Попробуйте:

tourists.removeAll(Collections.singleton(null));

Прочитайте Java API .Код выдаст java.lang.UnsupportedOperationException для неизменяемых списков (например, созданных с помощью Arrays.asList);см. этот ответ для более подробной информации.

101 голосов
/ 09 июля 2015

По состоянию на 2015 год это лучший способ (Java 8):

tourists.removeIf(Objects::isNull);

Примечание: Этот код будет выдавать java.lang.UnsupportedOperationException для списков фиксированного размера (например, созданныхс Arrays.asList), включая неизменяемые списки.

45 голосов
/ 13 марта 2013
list.removeAll(Collections.singleton(null));

Будет выброшено UnsupportedException , если вы используете его в Arrays.asList, потому что оно дает вам Неизменную копию, поэтому ее нельзя изменить.Смотрите ниже код.Он создает изменчивую копию и не выдает никаких исключений.

public static String[] clean(final String[] v) {
    List<String> list = new ArrayList<String>(Arrays.asList(v));
    list.removeAll(Collections.singleton(null));
    return list.toArray(new String[list.size()]);
}
18 голосов
/ 30 июля 2012

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

ImmutableList.copyOf(Iterables.filter(tourists, Predicates.notNull()))
18 голосов
/ 27 января 2011

Не эффективно, но коротко

while(tourists.remove(null));
7 голосов
/ 27 января 2011
 for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
      if (itr.next() == null) { itr.remove(); }
 }
3 голосов
/ 17 января 2017

Используя Java 8, вы можете сделать это, используя stream() и filter()

tourists = tourists.stream().filter(t -> t != null).collect(Collectors.toList())

или

tourists = tourists.stream().filter(Objects::nonNull).collect(Collectors.toList())

Для получения дополнительной информации: Java 8 - Потоки

3 голосов
/ 28 июля 2016

Класс Objects имеет nonNull Predicate, который можно использовать с filter.

Например:

tourists.stream().filter(Objects::nonNull).collect(Collectors.toList());
3 голосов
/ 15 ноября 2011

Существует простой способ удалить все значения null из collection. Вам нужно передать коллекцию, содержащую ноль в качестве параметра, removeAll() метод

List s1=new ArrayList();
s1.add(null);

yourCollection.removeAll(s1);
3 голосов
/ 28 мая 2017

Pre-Java 8 вы должны использовать:

tourists.removeAll(Collections.singleton(null));

Использование после Java 8:

tourists.removeIf(Objects::isNull);

Причина здесь в сложности времени. Проблема с массивами заключается в том, что операция удаления может занять O (n) времени для завершения. На самом деле в Java это копия массива оставшихся элементов, перемещаемых для замены пустого места. Многие другие решения, предлагаемые здесь, вызовут эту проблему. С технической точки зрения первый - это O (n * m), где m равно 1, потому что это одиночный ноль: так что O (n)

Вы должны удалить все синглтоны, внутренне это выполняет batchRemove (), который имеет позицию чтения и позицию записи. И повторяет список. Когда он достигает нуля, он просто повторяет позицию чтения на 1. Когда они одинаковы, он проходит, когда они различаются, он продолжает двигаться, копируя значения. Затем в конце он обрезается до размера.

Это эффективно делает это внутренне:

public static <E> void removeNulls(ArrayList<E> list) {
    int size = list.size();
    int read = 0;
    int write = 0;
    for (; read < size; read++) {
        E element = list.get(read);
        if (element == null) continue;
        if (read != write) list.set(write, element);
        write++;
    }
    if (write != size) {
        list.subList(write, size).clear();
    }
}

То, что вы можете явно увидеть, является операцией O (n).

Единственное, что может быть быстрее, - это если вы перебираете список с обоих концов, и когда вы нашли ноль, вы устанавливаете его значение равным значению, которое вы нашли в конце, и уменьшаете его. Итерировали, пока два значения не совпали. Вы бы испортили порядок, но значительно сократили бы количество значений вы ставите против тех, кого оставили в покое. Это хороший метод, который нужно знать, но он не сильно поможет, поскольку .set () в основном бесплатен, но эта форма удаления является полезным инструментом для вашего пояса.


for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
      if (itr.next() == null) { itr.remove(); }
 }

Хотя это кажется достаточно разумным, .remove () внутри итератора вызывает:

ArrayList.this.remove(lastRet);

Что снова является операцией O (n) при удалении. Он выполняет System.arraycopy (), что опять-таки не то, что вам нужно, если вы заботитесь о скорости. Это делает его n ^ 2.

Также есть:

while(tourists.remove(null));

Что есть O (m * n ^ 2). Здесь мы не только перебираем список. Мы повторяем весь список, каждый раз, когда мы совпадаем с нулем. Затем мы делаем n / 2 (средние) операции, чтобы System.arraycopy () выполнил удаление. Вы можете буквально отсортировать всю коллекцию между элементами со значениями и элементами с нулевыми значениями и обрезать окончание за меньшее время. На самом деле, это верно для всех сломанных. По крайней мере теоретически, фактическая system.arraycopy на самом деле не является операцией N на практике. В теории теория и практика - это одно и то же; на практике это не так.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...