Muszę obliczyć liczbę elementów Iterable
w języku Java. Wiem, że potrafię to zrobić:
Iterable values = ...
it = values.iterator();
while (it.hasNext()) {
it.next();
sum++;
}
Mógłbym też zrobić coś takiego, ponieważ nie potrzebuję już obiektów w Iterable:
it = values.iterator();
while (it.hasNext()) {
it.remove();
sum++;
}
Benchmark na małą skalę nie wykazał dużej różnicy w wydajności, żadnych komentarzy ani innych pomysłów na ten problem?
remove()
beznext()
wcześniejszego wezwania .Odpowiedzi:
TL; DR: Użyj metody narzędziowej
Iterables.size(Iterable)
wielkiej biblioteki Guava .Z dwóch fragmentów kodu powinieneś użyć pierwszego, ponieważ drugi usunie wszystkie elementy z
values
, więc później jest pusty. Zmiana struktury danych dla prostego zapytania, takiego jak jego rozmiar, jest bardzo nieoczekiwana.Wydajność zależy od struktury danych. Jeśli jest to na przykład w rzeczywistości a
ArrayList
, usuwanie elementów od początku (co robi twoja druga metoda) jest bardzo powolne (obliczenie rozmiaru staje się O (n * n) zamiast O (n) tak, jak powinno).Ogólnie rzecz biorąc, jeśli istnieje szansa, że
values
faktycznie jest to a,Collection
a nie tylkoIterable
, sprawdź to i zadzwońsize()
w przypadku:if (values instanceof Collection<?>) { return ((Collection<?>)values).size(); } // use Iterator here...
Wezwanie do
size()
woli zwykle znacznie szybciej niż zliczanie liczby elementów, a ten trik jest dokładnie to, coIterables.size(Iterable)
z Guava robi dla Ciebie.źródło
values
Jeśli pracujesz z Javą 8, możesz użyć:
Iterable values = ... long size = values.spliterator().getExactSizeIfKnown();
zadziała tylko wtedy, gdy iterowalne źródło ma określony rozmiar. Większość Spliterators for Collections to zrobić, ale możesz mieć problemy, jeśli pochodzą one z
HashSet
lubResultSet
na przykład.Możesz sprawdzić javadoc tutaj.
Jeśli Java 8 nie wchodzi w grę lub nie wiesz, skąd pochodzi iterowalność, możesz zastosować to samo podejście co guava:
if (iterable instanceof Collection) { return ((Collection<?>) iterable).size(); } else { int count = 0; Iterator iterator = iterable.iterator(); while(iterator.hasNext()) { iterator.next(); count++; } return count; }
źródło
To może trochę za późno, ale może komuś pomóc. Natknąłem się na podobny problem
Iterable
w mojej bazie kodu i rozwiązaniem było użyciefor each
bez jawnego wywołaniavalues.iterator();
.int size = 0; for(T value : values) { size++; }
źródło
Możesz przesłać swoją iterowalną listę na listę, a następnie użyć na niej .size ().
Dla jasności powyższa metoda będzie wymagać następującego importu:
import com.google.common.collect.Lists;
źródło
Ściśle mówiąc, Iterable nie ma rozmiaru. Pomyśl o strukturze danych jak o cyklu.
I pomyśl o następującej iterowalnej instancji, bez rozmiaru:
new Iterable(){ @Override public Iterator iterator() { return new Iterator(){ @Override public boolean hasNext() { return isExternalSystemAvailble(); } @Override public Object next() { return fetchDataFromExternalSystem(); }}; }};
źródło
Wybrałbym
it.next()
z prostego powodu, którynext()
jest gwarantowany do zaimplementowania, podczas gdyremove()
jest to operacja opcjonalna.źródło
remove
zostało już zauważone jako niewłaściwy sposób liczenia elementów anIterator
, więc tak naprawdę nie ma znaczenia, czy rzecz, której nie zamierzamy zrobić, jest zaimplementowana, czy nie.remove
jest wdrożony, dlaczego byłoby źle z niego korzystać? Przy okazji, głosy przeciwne są zwykle używane do złych odpowiedzi lub odpowiedzi, które dają złą radę. Nie rozumiem, jak ta odpowiedź kwalifikuje się do czegoś takiego.java 8 i nowsze
StreamSupport.stream(data.spliterator(), false).count();
źródło
Jak dla mnie to tylko różne metody. Pierwsza z nich pozostawia obiekt, na którym iterujesz, bez zmian, podczas gdy sekundy pozostawiają go pustym. Pytanie brzmi, co chcesz robić. Złożoność usuwania opiera się na implementacji iterowalnego obiektu. Jeśli używasz Kolekcji - po prostu uzyskaj rozmiar taki, jaki zaproponował Kazekage Gaara - zazwyczaj jest to najlepsze podejście pod względem wydajności.
źródło
Dlaczego po prostu nie użyjesz
size()
metody na swoim,Collection
aby uzyskać liczbę elementów?Iterator
służy tylko do iteracji, nic więcej.źródło
Iterator
iIterable
. Zobacz głosowaną odpowiedź, aby znaleźć właściwy sposób.Zamiast używać pętli i zliczać każdy element lub korzystać z biblioteki innej firmy, możemy po prostu wpisać iterowalną iterację w ArrayList i uzyskać jej rozmiar.
źródło