Iterator niekoniecznie musi odpowiadać „zliczeniu” ...
Oliver Charlesworth
Iteratory są tym, czym są; aby iterować do następnego obiektu kolekcji (może to być coś takiego jak zestaw, tablica itp.) Dlaczego muszą podawać rozmiar, kiedy nie obchodzi ich, po co próbują iterować? to provide an implementation-independent method for access, in which the user does not need to know whether the underlying implementation is some form of array or of linked list, and allows the user go through the collection without explicit indexing.penguin.ewu.edu/~trolfe/LinkedSort/Iterator.html
ecle
Odpowiedzi:
67
Jeśli masz właśnie iterator, musisz to zrobić - nie wie, ile elementów zostało do iteracji, więc nie możesz zapytać go o ten wynik. Istnieją metody narzędziowe, które wydają się to robić (na przykład Iterators.size()w guawie), ale pod spodem wykonują w przybliżeniu tę samą operację.
Jednak wiele iteratorów pochodzi z kolekcji, w przypadku których często można zapytać o ich rozmiar. A jeśli jest to klasa utworzona przez użytkownika, dla której otrzymujesz iterator, możesz poszukać metody size () dla tej klasy.
Krótko mówiąc, w sytuacji, gdy masz tylko iterator, nie ma lepszego sposobu, ale znacznie częściej niż nie masz dostępu do bazowej kolekcji lub obiektu, z którego możesz bezpośrednio uzyskać rozmiar.
Uważaj na efekt uboczny Iterators.size(...)(wspomniany w innych komentarzach poniżej oraz w java-doc): "Zwraca liczbę elementów pozostałych w iteratorze. Iterator zostanie wyczerpany: jego metoda hasNext () zwróci wartość false." Oznacza to, że nie możesz już używać Iteratora. Lists.newArrayList(some_iterator);może pomóc.
Korzystając z biblioteki Guava , inną opcją jest przekonwertowanie Iterablepliku na plik List.
List list =Lists.newArrayList(some_iterator);int count = list.size();
Użyj tego, jeśli potrzebujesz również uzyskać dostęp do elementów iteratora po uzyskaniu jego rozmiaru. Używając Iterators.size()nie masz już dostępu do iterowanych elementów.
@LoveToCode Mniej wydajne niż przykład w pierwotnym pytaniu
zima
2
Oczywiście, tworzenie nowego obiektu ze wszystkimi elementami jest wolniejsze niż zwykłe iterowanie i odrzucanie. IMHO, to rozwiązanie jest jednowierszowe, które poprawia czytelność kodu. Używam go często do kolekcji z kilkoma elementami (do 1000) lub gdy szybkość nie jest problemem.
tashuhka
7
Jeśli wszystko, co masz, to iterator, to nie, nie ma „lepszego” sposobu. Jeśli iterator pochodzi z kolekcji, możesz wybrać rozmiar.
Pamiętaj, że Iterator to tylko interfejs do przechodzenia przez różne wartości, bardzo dobrze byłoby mieć taki kod
newIterator<Long>(){finalRandom r =newRandom();@Overridepublicboolean hasNext(){returntrue;}@OverridepublicLong next(){return r.nextLong();}@Overridepublicvoid remove(){thrownewIllegalArgumentException("Not implemented");}};
lub
newIterator<BigInteger>(){BigInteger next =BigInteger.ZERO;@Overridepublicboolean hasNext(){returntrue;}@OverridepublicBigInteger next(){BigInteger current = next;
next = next.add(BigInteger.ONE);return current;}@Overridepublicvoid remove(){thrownewIllegalArgumentException("Not implemented");}};
Nie ma bardziej wydajnego sposobu, jeśli wszystko, co masz, to iterator. A jeśli iterator może być użyty tylko raz, to uzyskanie licznika przed uzyskaniem zawartości iteratora jest ... problematyczne.
Rozwiązaniem jest albo zmiana aplikacji, aby nie potrzebowała liczenia, albo uzyskanie liczby w inny sposób. (Na przykład podaj Collectionraczej niż Iterator...)
to provide an implementation-independent method for access, in which the user does not need to know whether the underlying implementation is some form of array or of linked list, and allows the user go through the collection without explicit indexing.
penguin.ewu.edu/~trolfe/LinkedSort/Iterator.htmlOdpowiedzi:
Jeśli masz właśnie iterator, musisz to zrobić - nie wie, ile elementów zostało do iteracji, więc nie możesz zapytać go o ten wynik. Istnieją metody narzędziowe, które wydają się to robić (na przykład
Iterators.size()
w guawie), ale pod spodem wykonują w przybliżeniu tę samą operację.Jednak wiele iteratorów pochodzi z kolekcji, w przypadku których często można zapytać o ich rozmiar. A jeśli jest to klasa utworzona przez użytkownika, dla której otrzymujesz iterator, możesz poszukać metody size () dla tej klasy.
Krótko mówiąc, w sytuacji, gdy masz tylko iterator, nie ma lepszego sposobu, ale znacznie częściej niż nie masz dostępu do bazowej kolekcji lub obiektu, z którego możesz bezpośrednio uzyskać rozmiar.
źródło
Iterators.size(...)
(wspomniany w innych komentarzach poniżej oraz w java-doc): "Zwraca liczbę elementów pozostałych w iteratorze. Iterator zostanie wyczerpany: jego metoda hasNext () zwróci wartość false." Oznacza to, że nie możesz już używać Iteratora.Lists.newArrayList(some_iterator);
może pomóc.Korzystanie z biblioteki Guava :
Wewnętrznie po prostu iteruje po wszystkich elementach, więc jest to tylko dla wygody.
źródło
Twój kod da ci wyjątek, gdy dojdziesz do końca iteratora. Mógłbyś:
Gdybyś miał dostęp do podstawowej kolekcji, mógłbyś zadzwonić
coll.size()
...EDYTUJ OK, poprawiłeś ...
źródło
Zawsze będziesz musiał iterować. Jednak możesz użyć Java 8, 9 do liczenia bez jawnego zapętlania:
Oto test:
To drukuje:
Co ciekawe, możesz zrównoleglać tutaj operację zliczania, zmieniając
parallel
flagę w tym wywołaniu:źródło
Korzystając z biblioteki Guava , inną opcją jest przekonwertowanie
Iterable
pliku na plikList
.Użyj tego, jeśli potrzebujesz również uzyskać dostęp do elementów iteratora po uzyskaniu jego rozmiaru. Używając
Iterators.size()
nie masz już dostępu do iterowanych elementów.źródło
Jeśli wszystko, co masz, to iterator, to nie, nie ma „lepszego” sposobu. Jeśli iterator pochodzi z kolekcji, możesz wybrać rozmiar.
Pamiętaj, że Iterator to tylko interfejs do przechodzenia przez różne wartości, bardzo dobrze byłoby mieć taki kod
lub
źródło
Nie ma bardziej wydajnego sposobu, jeśli wszystko, co masz, to iterator. A jeśli iterator może być użyty tylko raz, to uzyskanie licznika przed uzyskaniem zawartości iteratora jest ... problematyczne.
Rozwiązaniem jest albo zmiana aplikacji, aby nie potrzebowała liczenia, albo uzyskanie liczby w inny sposób. (Na przykład podaj
Collection
raczej niżIterator
...)źródło
dla Java 8 możesz użyć,
źródło
obiekt iterator zawiera taką samą liczbę elementów, jaką zawierała Twoja kolekcja.
Ale zamiast pobierać rozmiar iteratora i iterować przez indeks 0 do tego rozmiaru, lepiej jest wykonać iterację metodą next () iteratora.
źródło
a
, ale tylkoi
?