[java] 반복기의 개수 / 길이 / 크기를 얻는 가장 좋은 방법은 무엇입니까?

반복기의 수를 얻는 “계산적으로”빠른 방법이 있습니까?

int i = 0;
for ( ; some_iterator.hasNext() ; ++i ) some_iterator.next();

… CPU 사이클 낭비처럼 보입니다.



답변

반복자를 가지고 있다면 그게해야 할 일입니다. 반복 할 항목이 몇 개 남았는지 알지 못하기 때문에 해당 결과를 쿼리 할 수 ​​없습니다. 이를 수행하는 것처럼 보이는 유틸리티 메서드 (예 : Iterators.size()Guava)가 있지만 그 아래에서는 거의 동일한 작업을 수행하고 있습니다.

그러나 많은 이터레이터는 컬렉션에서 가져 오므로 종종 크기를 쿼리 할 수 ​​있습니다. 그리고 그것이 반복자를 얻고있는 사용자가 만든 클래스 인 경우 해당 클래스에 size () 메서드를 제공 할 수 있습니다.

간단히 말해서, 반복자 있는 상황에서 더 좋은 방법은 없지만 크기를 직접 가져올 수있는 기본 컬렉션이나 개체에 액세스 할 수있는 경우가 훨씬 더 많습니다.


답변

Guava 라이브러리 사용 :

int size = Iterators.size(iterator);

내부적으로는 모든 요소를 ​​반복하므로 편의를 위해.


답변

반복자의 끝에 도달하면 코드에서 예외가 발생합니다. 다음과 같이 할 수 있습니다.

int i = 0;
while(iterator.hasNext()) {
    i++;
    iterator.next();
}

기본 컬렉션에 대한 액세스 권한이있는 경우 다음을 호출 할 수 있습니다 coll.size().

수정
확인 수정했습니다 …


답변

항상 반복해야합니다. 그러나 Java 8, 9를 사용하여 명시 적으로 반복하지 않고도 계산을 수행 할 수 있습니다.

Iterable<Integer> newIterable = () -> iter;
long count = StreamSupport.stream(newIterable.spliterator(), false).count();

다음은 테스트입니다.

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

이것은 다음을 인쇄합니다.

5

흥미롭게 parallel도이 호출 에서 플래그를 변경하여 여기서 카운트 작업을 병렬화 할 수 있습니다 .

long count = StreamSupport.stream(newIterable.spliterator(), *true*).count();


답변

사용 구아바 라이브러리를 , 또 다른 옵션은 변환하는 IterableA를 List.

List list = Lists.newArrayList(some_iterator);
int count = list.size();

크기를 가져온 후 반복기의 요소에 액세스해야하는 경우에도이를 사용하십시오. 사용 Iterators.size()하면 더 이상 반복 된 요소에 액세스 할 수 없습니다.


답변

당신이 가진 모든 것이 반복자라면, “더 나은”방법은 없습니다. 이터레이터가 컬렉션에서 나온다면 크기만큼 할 수 있습니다.

Iterator는 고유 한 값을 탐색하기위한 인터페이스 일 뿐이므로 다음과 같은 코드를 사용하는 것이 좋습니다.

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

또는

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


답변

반복자 만 있으면 더 효율적인 방법은 없습니다. 그리고 반복기를 한 번만 사용할 수 있다면 반복자의 내용을 얻기 전에 개수를 얻는 것이 문제가됩니다.

해결책은 카운트가 필요하지 않도록 애플리케이션을 변경하거나 다른 방법으로 카운트를 얻는 것입니다. (예를 들어 … Collection보다는 a를 전달하십시오 Iterator.)