2011-01-27 28 views
151

Trato con un bucle de esa manera¿Cómo eliminar todos los elementos nulos de ArrayList o String Array?

// ArrayList tourists 

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

pero no es agradable. ¿Alguien puede sugerirme una mejor solución?


Algunas referencias útiles para hacer una mejor decisión:

While loop, For loop and Iterator Performance Test

+2

uso 'Iterator'? Dig java-doc. http://download.oracle.com/javase/6/docs/api/java/util/Iterator.html#remove%28%29 – Nishant

Respuesta

317

Probar:

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

Leer el Java API. El código arrojará java.lang.UnsupportedOperationException para listas inmutables (como las creadas con Arrays.asList); ver this answer para más detalles.

+0

Detalle de implementación pequeño: esta llamada cambia la capacidad de la lista. –

+5

La complejidad temporal de 'List.removeAll()' es ** n^2 **. Solo digo. – Hemanth

+4

Para Java 8 o posterior, consulte la respuesta de @ MarcG a continuación. –

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

Esto puede ser más útil cuando tiene que eliminar elementos al atravesar. La coincidencia es que estaba anulando los elementos que tratar de usar 'removeAll (.. null ..)'. ¡Gracias! – Mustafa

+0

Puede que sea mejor configurar los valores como nulos y luego eliminarlos al final. El loteEliminar en removeAll atraviesa la lista, con una ubicación de lectura y escritura, e itera la lista una vez, moviendo la lectura pero no la escritura cuando llega a un valor nulo. .remove() podría tener que copiar todo el conjunto cada vez que se llame. – Tatarize

17

no es eficiente, pero corto

while(tourists.remove(null)); 
+1

Lamentablemente, su solución fue la única que funcionó para mí ... ¡gracias! – Pkmmte

+0

simple y rápido –

+0

excelente! ¡Favorito! – Flax

1

He jugado un poco con esto y descubrió que TrimToSize() parece funcionar. Estoy trabajando en la plataforma Android, por lo que podría ser diferente.

+2

Según el javadoc, 'trimToSize' no modifica el contenido de una' ArrayList'. Si esto es diferente en Android, probablemente sea un error. – fabian

3

hay una manera fácil de eliminar todos los valores de nullcollection .tiene tienen que pasar una colección que contiene nulo como un parámetro para removeAll() método

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

yourCollection.removeAll(s1); 
+0

Esto funcionó lo mejor para mí. También le permite agregar fácilmente más de una entrada en su "matriz de filtros" que pasa al método removeAll de la colección original. –

16

Si prefiere los objetos de datos inmutables, o si simplemente No quiero ser destructivo para la lista de entrada, puedes usar los predicados de Guava.

ImmutableList.copyOf(Iterables.filter(tourists, Predicates.notNull())) 
42
list.removeAll(Collections.singleton(null)); 

It will Throws UnsupportedException if you use it on Arrays.asList because it give you Immutable copy so it can not be modified. See below the code. It creates Mutable copy and will not throw any exception.

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()]); 
} 
2

Ésta es la manera fácil de eliminar los valores nulos por defecto de ArrayList

 tourists.removeAll(Arrays.asList(null)); 

lo contrario valor

cadena "nula" Eliminar de ArrayList

 tourists.removeAll(Arrays.asList("null")); 
1

Podemos usar iterator para lo mismo para eliminar todos los valores nulos.

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

A partir de 2015, esta es la mejor manera (Java 8):

tourists.removeIf(Objects::isNull); 

Nota: Este código tirará java.lang.UnsupportedOperationException para las listas de tamaño fijo (tales como los que crea Arrays.asList), incluidas las listas inmutables.

+1

"Mejor" de qué manera? ¿Es más rápido que otros enfoques? ¿O es simplemente más legible en virtud de la brevedad? –

+7

No solo por brevedad, sino porque es más expresivo. Casi puede leerlo: "De los turistas, elimine si el objeto es nulo". Además, la forma antigua es crear una nueva colección con un único objeto nulo, y luego pedirle que elimine el contenido de una colección de la otra. Parece un truco, ¿no crees? Con respecto a la velocidad, usted tiene un punto, si la lista es realmente grande y el rendimiento es una preocupación, le sugiero probar en ambos sentidos. Mi suposición sería que 'removeIf' es más rápido, pero es una suposición. – MarcG

+1

'Arrays.asList' no es _immutable_. Es de tamaño fijo. – turbanoff

1

Utilicé la interfaz de transmisión junto con la operación de secuencia y obtuve y un método auxiliar para generar una nueva lista.

tourists.stream().filter(this::isNotNull).collect(Collectors.toList()); 

private <T> boolean isNotNull(final T item) { 
    return item != null; 
} 
+2

'tourists.stream(). Filter (s -> s! = Null) .collect (Collectors.toList());' – 1ac0

+0

@LadislavDANKO o 'Objects :: nonNull' para el valor semántico. – Moira

3

La clase Objects tiene una nonNullPredicate que se puede utilizar con filter.

Por ejemplo:

tourists.stream().filter(Objects::nonNull).collect(Collectors.toList()); 
+1

Bienvenido a Stack Overflow. Al responder preguntas, intente agregar una explicación de su código. Regrese y edite su respuesta para incluir más información. – Tyler

2

Uso de Java 8, puede hacerlo utilizando stream() y filter()

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

o

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

Para más información: Java 8 - Streams

1

Pre-8 de Java que puedes usar:

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

Post-Java 8 uso:

tourists.removeIf(Objects::isNull); 

La razón aquí es la complejidad de tiempo. El problema con las matrices es que una operación de eliminación puede tomar O (n) tiempo para completarse. Realmente en Java, esta es una copia de la matriz de los elementos restantes que se mueven para reemplazar la mancha vacía. Muchas otras soluciones que se ofrecen aquí desencadenarán este problema. El primero es técnicamente O (n * m) donde m es 1 porque es un nulo singleton: así que O (n)

Debe eliminar Todo del singleton, internamente hace un batchRemove() que tiene una posición de lectura y una escribir posición Y repite la lista. Cuando llega a un nulo, simplemente itera la posición de lectura en 1. Cuando pasan lo mismo, cuando son diferentes se mueve a lo largo de la copia de los valores. Luego, al final, se ajusta a medida.

Lo hace efectivamente esto internamente:

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

que se puede ver de forma explícita es un O (n) la operación.

Lo único que podría ser más rápido es si itera la lista desde ambos extremos, y cuando encuentra un valor nulo, establece su valor igual al valor que encontró al final y decrementa ese valor. Y se repitió hasta que los dos valores coincidieron. Desordenarías el orden, pero reducirías enormemente el número de valores que estableces frente a los que dejaste solos. Lo cual es un buen método para saber pero no ayudará mucho porque .set() es básicamente gratis, pero esa forma de eliminar es una herramienta útil para tu cinturón.


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

Si bien esto parece bastante razonable, el .Remove() del iterador llama internamente:

ArrayList.this.remove(lastRet); 

que es otra vez la operación O (n) dentro de la eliminación. Hace una System.arraycopy() que de nuevo no es lo que quieres, si te importa la velocidad. Esto lo hace n^2.

Hay también:

while(tourists.remove(null)); 

Qué es O (m * n^2). Aquí no solo iteramos la lista. Reiteramos toda la lista, cada vez que hacemos coincidir el nulo. Luego hacemos n/2 (promedio) de operaciones para hacer el System.arraycopy() para realizar la eliminación. Podría literalmente clasificar la colección completa entre elementos con valores y elementos con valores nulos y recortar la terminación en menos tiempo. De hecho, eso es cierto para todos los rotos. Al menos en teoría, el sistema real.arraycopy no es realmente una operación N en la práctica. En teoría, la teoría y la práctica son la misma cosa; en la práctica, no lo son.

0

Usando Java 8 esto se puede realizar de varias maneras usando corrientes, corrientes paralelas y removeIf método:

List<String> stringList = new ArrayList<>(Arrays.asList(null, "A", "B", null, "C", null)); 
List<String> listWithoutNulls1 = stringList.stream() 
       .filter(Objects::nonNull) 
       .collect(Collectors.toList()); //[A,B,C] 
List<String> listWithoutNulls2 = stringList.parallelStream() 
       .filter(Objects::nonNull) 
       .collect(Collectors.toList()); //[A,B,C] 
stringList.removeIf(Objects::isNull); //[A,B,C] 

La corriente paralela hará uso de procesadores disponibles y acelerará el proceso de tamaño razonable liza. Siempre es recomendable hacer una evaluación comparativa antes de usar transmisiones.

0

similares a @Lithium respuesta, pero no lanzar una "lista no puede contener nulos tipo" Error:

list.removeAll(Collections.<T>singleton(null)); 
Cuestiones relacionadas