Czy istnieje „obliczeniowy” szybki sposób uzyskania liczby iteratora?
int i = 0;
for ( ; some_iterator.hasNext() ; ++i ) some_iterator.next();
... wygląda na stratę cykli procesora.
Czy istnieje „obliczeniowy” szybki sposób uzyskania liczby iteratora?
int i = 0;
for ( ; some_iterator.hasNext() ; ++i ) some_iterator.next();
... wygląda na stratę cykli procesora.
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
Odpowiedzi:
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.
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 :
int size = Iterators.size(iterator);
Wewnętrznie po prostu iteruje po wszystkich elementach, więc jest to tylko dla wygody.
Twój kod da ci wyjątek, gdy dojdziesz do końca iteratora. Mógłbyś:
int i = 0;
while(iterator.hasNext()) {
i++;
iterator.next();
}
Gdybyś miał dostęp do podstawowej kolekcji, mógłbyś zadzwonić coll.size()
...
EDYTUJ OK, poprawiłeś ...
Zawsze będziesz musiał iterować. Jednak możesz użyć Java 8, 9 do liczenia bez jawnego zapętlania:
Iterable<Integer> newIterable = () -> iter;
long count = StreamSupport.stream(newIterable.spliterator(), false).count();
Oto test:
public static void main(String[] args) throws IOException {
Iterator<Integer> iter = Arrays.asList(1, 2, 3, 4, 5).iterator();
Iterable<Integer> newIterable = () -> iter;
long count = StreamSupport.stream(newIterable.spliterator(), false).count();
System.out.println(count);
}
To drukuje:
5
Co ciekawe, możesz zrównoleglać tutaj operację zliczania, zmieniając parallel
flagę w tym wywołaniu:
long count = StreamSupport.stream(newIterable.spliterator(), *true*).count();
Korzystając z biblioteki Guava , inną opcją jest przekonwertowanie Iterable
pliku 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.
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
new Iterator<Long>() {
final Random r = new Random();
@Override
public boolean hasNext() {
return true;
}
@Override
public Long next() {
return r.nextLong();
}
@Override
public void remove() {
throw new IllegalArgumentException("Not implemented");
}
};
lub
new Iterator<BigInteger>() {
BigInteger next = BigInteger.ZERO;
@Override
public boolean hasNext() {
return true;
}
@Override
public BigInteger next() {
BigInteger current = next;
next = next.add(BigInteger.ONE);
return current;
}
@Override
public void remove() {
throw new IllegalArgumentException("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 Collection
raczej niż Iterator
...)
obiekt iterator zawiera taką samą liczbę elementów, jaką zawierała Twoja kolekcja.
List<E> a =...;
Iterator<E> i = a.iterator();
int size = a.size();//Because iterators size is equal to list a's size.
Ale zamiast pobierać rozmiar iteratora i iterować przez indeks 0 do tego rozmiaru, lepiej jest wykonać iterację metodą next () iteratora.
a
, ale tylko i
?