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


96

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

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

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


2
반복자는 ...에 "계산"뭔가에 반드시 대응을하지 않습니다
올리버 찰스 워드

반복자는 그 자체입니다. 컬렉션의 다음 객체로 반복합니다 (세트, 배열 등과 같은 것이 될 수 있습니다.) 반복하려는 대상에 신경 쓰지 않을 때 크기를 알려야하는 이유는 무엇입니까? 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

답변:


67

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

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

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


Iterators.size(...)(아래의 다른 주석과 java-doc에 언급 된) 의 부작용에주의하십시오 . "반복자에 남아있는 요소의 수를 반환합니다. 반복자는 고갈 된 상태로 남습니다. hasNext () 메서드는 false를 반환합니다." 즉, 나중에 더 이상 Iterator를 사용할 수 없습니다. Lists.newArrayList(some_iterator);도움이 될 수 있습니다.
MichaelCkr

91

Guava 라이브러리 사용 :

int size = Iterators.size(iterator);

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


8
이것은 매우 우아합니다. 반복자를 사용하고 있다는 것을 기억하십시오 (즉, 반복자는 나중에 비어 있음)
lolski

1
이것은 "계산적으로 빠르다"는 것이 아니라 반복기를 소비하는 원치 않는 부작용이있는 편리한 방법입니다.
Zak

어떻게 작동하는지 설명해 주시겠습니까? @Andrejs List <Tuple2 <String, Integer >> wordCountsWithGroupByKey = wordsPairRdd.groupByKey () .mapValues ​​(intIterable-> Iterables.size (intIterable)). collect (); System.out.println ( "wordCountsWithGroupByKey :"+ wordCountsWithGroupByKey); "Iterables.size (intIterable)?
Aditya Verma

15

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

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

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

수정 확인 수정했습니다 ...


이것이 얼마나 효율적입니까? 반복자가 백만 개의 값과 같으면 어떨까요?
Micro

4
@Micro 기술적으로 반복자는 무한 할 수 있습니다.이 경우 루프는 영원히 계속됩니다.
assylias

12

항상 반복해야합니다. 그러나 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();

8

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

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

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


2
@LoveToCode 원래 질문의 예보다 덜 효율적입니다
Winter

2
물론 모든 요소가 포함 된 새 개체를 만드는 것은 단순히 반복하고 삭제하는 것보다 느립니다. IMHO,이 솔루션은 코드 가독성을 향상시키는 한 줄짜리 솔루션입니다. 요소가 거의없는 컬렉션 (최대 1000 개)이나 속도가 문제가되지 않는 컬렉션에 많이 사용합니다.
tashuhka

7

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

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

4

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

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


0

대한 자바 (8) 당신이 사용할 수있는,

public static int getIteratorSize(Iterator iterator){
        AtomicInteger count = new AtomicInteger(0);
        iterator.forEachRemaining(element -> {
            count.incrementAndGet();
        });
        return count.get();
    }

-5

iterator 객체는 컬렉션에 포함 된 것과 동일한 수의 요소를 포함합니다.

List<E> a =...;
Iterator<E> i = a.iterator();
int size = a.size();//Because iterators size is equal to list a's size.

그러나 반복기의 크기를 가져와 인덱스 0을 통해 해당 크기로 반복 하는 대신 반복기의 next () 메서드를 반복하는 것이 좋습니다 .


우리는 무엇을하지 않은 경우 a만, i?
Tvde1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.