2012-11-09 14 views
7

Chciałbym usunąć element z ArrayList w Javie, jeśli spełnia on określone kryteria.Usuwanie obiektów z tablicy ArrayList na podstawie podanych kryteriów

tj:

for (Pulse p : pulseArray) { 
    if (p.getCurrent() == null) { 
     pulseArray.remove(p); 
    } 
} 

mogę zrozumieć, dlaczego to nie działa, ale to, co jest dobrym sposobem, aby to zrobić?

+0

Nie tylko to nie działa, ale nawet gdyby tak się stało praca miałoby to fatalne wyniki. Jest to algorytm O (n^2), ponieważ musisz sprawdzić każdy element tablicy do tego, który usuwasz. Optymalnym algorytmem jest O (n). –

+0

@MarkByers "sprawdź każdy element tablicy" to O (n), dlaczego myślisz, że to O (n^2)? – jlordo

+0

@jlordo: 'list.remove (object)' jest operacją O (n). Wykonuje się O (n) razy, ponieważ jest w pętli. To daje O (n * n). –

Odpowiedz

11

Musisz użyć Iterator iteracyjne i funkcja remove z iteracyjnej (nie listy):

Iterator<Pulse> iter = pulseArray.iterator(); 
while (iter.hasNext()) { 
    Pulse p = iter.next(); 
    if (p.getCurrent()==null) iter.remove(); 
} 

pamiętać, że funkcja Iterator#remove mówi się optionnal ale jest realizowane przez Iterator ArrayList.

Oto kod tej konkretnej funkcji z ArrayList.java:

765   public void remove() { 
766    if (lastRet < 0) 
767     throw new IllegalStateException(); 
768    checkForComodification(); 
769 
770    try { 
771     ArrayList.this.remove(lastRet); 
772     cursor = lastRet; 
773     lastRet = -1; 
774     expectedModCount = modCount; 
775    } catch (IndexOutOfBoundsException ex) { 
776     throw new ConcurrentModificationException(); 
777    } 
778   } 
779 
780   final void checkForComodification() { 
781    if (modCount != expectedModCount) 
782     throw new ConcurrentModificationException(); 
783   } 
784  } 

Linia expectedModCount = modCount; dlatego nie rzuci wyjątek, gdy go używać podczas iteracji.

+0

Z technicznego punktu widzenia, pętla rozszerzona za pomocą iteratora. Czy możesz podać przykład tego, co musiałby zrobić? Należy również zauważyć, że nie wszystkie iteratory będą faktycznie implementować metodę remove i będą zgłaszać wyjątek "nie zaimplementowany". –

+0

@ Clockwork-Muse Tak, ale wewnętrzny iterator ArrayList wykonuje to. –

0

Nie można zmienić kolekcji, którą iterujesz, używając metod z kolekcji. Jednak niektóre iteratory (w tym iteratory w wersji ArrayList s) obsługują metodę remove(), która umożliwia usuwanie metod w kolejności, w której jest wykonywana iteracja.

Iterator<Pulse> iterator = pulseArray.iterator(); 
while (iterator.hasNext()) { 
    Pulse p = iterator.next(); 
    if (p.getCurrent() == null) { 
    iterator.remove(); 
    } 
} 
0

Kiedy jesteś usunięcie elementu z samej liście, indeks zostaje zakłócony. Spróbuj trochę inaczej, jak poniżej:

for (int i=0; i < pulseArray.size(); i++) { 
    Pulse p = (Pulse)pulseArray.get(i); 
    if (p.getCurrent() == null) { 
     pulseArray.remove(p); 
     i--;//decrease the counter by one 
    } 
    } 
-1

Korzystanie iterator nie daje moc modyfikowania listy podczas iteracja ArrayList

2

Jako alternatywny do korzystania iterator, można korzystać z biblioteki Guava kolekcjach. Ma to tę zaletę, że jest bardziej functional (jeśli jesteś do tego rodzaju rzeczy):

Predicate<Pulse> hasCurrent = new Predicate<Pulse>() { 
    @Override public boolean apply(Pulse input) { 
    return (input.getCurrent() != null); 
    } 
}; 

pulseArray = Lists.newArrayList(Collections2.filter(pulseArray, hasCurrent)); 
1

ma potrzeby korzystania iterator. Z Java 8 (funkcje strumieniowania i filtrowania oraz lambdy) możesz to zrobić za pomocą jednej linii. Na przykład. wymagany kod, który robi operacja została określona będzie:

pulseArray = pulseArray.stream().filter(pulse -> pulse != null).collect(Collectors.toList()); 
+2

Powinieneś użyć 'removeIf' zamiast tworzyć nową listę ... – assylias

+0

Możesz także użyć' Objects :: nonNull'. – shmosel

1

Można użyć Collection::removeIf(Predicate filter), oto prosty przykład:

final Collection<Integer> list = new ArrayList<>(Arrays.asList(1, 2)); 
list.removeIf(value -> value < 2); 
System.out.println(list); // outputs "[2]" 
+0

To działa dla mnie –

Powiązane problemy