วิธีที่ดีที่สุดในการนับจำนวน / ความยาว / ขนาดของตัววนซ้ำคืออะไร?


100

มีวิธีที่รวดเร็วในการนับจำนวนตัววนซ้ำหรือไม่?

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

... ดูเหมือนจะเสียรอบการทำงานของ CPU


2
ตัววนซ้ำไม่จำเป็นต้องตรงกับบางสิ่งที่มี "จำนวน" ...
Oliver Charlesworth

Iterators คือสิ่งที่พวกเขา; เพื่อวนซ้ำไปยังออบเจ็กต์ถัดไปของคอลเลกชัน (อาจเป็นอะไรก็ได้เช่น set อาร์เรย์ ฯลฯ ) ทำไมพวกเขาถึงต้องบอกขนาดในเมื่อพวกเขาไม่สนใจว่าพวกเขาพยายามจะทำซ้ำ 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 () ของมันจะคืนค่าเป็นเท็จ" นั่นหมายความว่าคุณจะไม่สามารถใช้ 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()...

แก้ไข ตกลงคุณได้แก้ไข ...


มันมีประสิทธิภาพแค่ไหน? จะเกิดอะไรขึ้นถ้าตัววนซ้ำเหมือนค่าล้าน?
ไมโคร

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

การใช้ห้องสมุดฝรั่งอีกทางเลือกหนึ่งคือการแปลงไปIterableList

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

ใช้สิ่งนี้หากคุณต้องการเข้าถึงองค์ประกอบของตัววนซ้ำหลังจากได้ขนาดแล้ว เมื่อใช้Iterators.size()คุณจะไม่สามารถเข้าถึงองค์ประกอบที่ทำซ้ำได้อีกต่อไป


2
@LoveToCode มีประสิทธิภาพน้อยกว่าตัวอย่างในคำถามเดิม
ฤดูหนาว

2
แน่นอนว่าการสร้างออบเจ็กต์ใหม่ที่มีองค์ประกอบทั้งหมดนั้นทำได้ช้ากว่าการทำซ้ำและทิ้ง IMHO โซลูชันนี้เป็นหนึ่งซับที่ช่วยเพิ่มความสามารถในการอ่านโค้ด ฉันใช้มันมากสำหรับคอลเลกชันที่มีองค์ประกอบน้อย (มากถึง 1,000 ชิ้น) หรือเมื่อความเร็วไม่ใช่ปัญหา
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มากกว่าIterator... )


0

สำหรับJava 8คุณสามารถใช้ได้

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

-6

ออบเจ็กต์ตัววนซ้ำมีองค์ประกอบจำนวนเท่ากันกับสิ่งที่คอลเลกชันของคุณมีอยู่

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

แต่แทนที่จะได้รับขนาดของตัววนซ้ำและวนซ้ำผ่านดัชนี 0 เป็นขนาดนั้นจะเป็นการดีกว่าที่จะวนซ้ำด้วยวิธีการถัดไป ()ของตัววนซ้ำ


1
จะเป็นอย่างไรถ้าเราไม่มีaแต่เพียงอย่างเดียวi?
Tvde1
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.