มีวิธีที่รวดเร็วในการนับจำนวนตัววนซ้ำหรือไม่?
int i = 0;
for ( ; some_iterator.hasNext() ; ++i ) some_iterator.next();
... ดูเหมือนจะเสียรอบการทำงานของ CPU
มีวิธีที่รวดเร็วในการนับจำนวนตัววนซ้ำหรือไม่?
int i = 0;
for ( ; some_iterator.hasNext() ; ++i ) some_iterator.next();
... ดูเหมือนจะเสียรอบการทำงานของ CPU
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
คำตอบ:
หากคุณเพิ่งมีตัววนซ้ำนั่นคือสิ่งที่คุณต้องทำ - ไม่รู้ว่ามีกี่รายการที่เหลือให้ทำซ้ำดังนั้นคุณจึงไม่สามารถค้นหาผลลัพธ์นั้นได้ มีวิธียูทิลิตี้ที่ดูเหมือนจะทำสิ่งนี้ (เช่นIterators.size()
ใน Guava) แต่ภายใต้พวกเขากำลังดำเนินการโดยประมาณเดียวกัน
อย่างไรก็ตามตัววนซ้ำจำนวนมากมาจากคอลเล็กชันซึ่งคุณมักจะค้นหาขนาดของมันได้ และถ้าเป็นคลาสที่ผู้ใช้สร้างขึ้นคุณจะได้รับตัววนซ้ำคุณสามารถระบุวิธีการ size () ในคลาสนั้นได้
ในระยะสั้นในสถานการณ์ที่คุณมีเพียงตัววนซ้ำไม่มีวิธีใดที่ดีไปกว่านี้ แต่บ่อยครั้งกว่าที่คุณไม่สามารถเข้าถึงคอลเลกชันหรือวัตถุที่อยู่ข้างใต้ซึ่งคุณอาจสามารถรับขนาดได้โดยตรง
Iterators.size(...)
(ที่กล่าวถึงในความคิดเห็นอื่น ๆ ด้านล่างและใน java-doc): "ส่งคืนจำนวนองค์ประกอบที่เหลืออยู่ในตัววนซ้ำตัววนซ้ำจะถูกปล่อยให้หมด: เมธอด hasNext () ของมันจะคืนค่าเป็นเท็จ" นั่นหมายความว่าคุณจะไม่สามารถใช้ Iterator ได้อีกต่อไปในภายหลัง Lists.newArrayList(some_iterator);
อาจช่วยได้
การใช้ห้องสมุด 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();
การใช้ห้องสมุดฝรั่งอีกทางเลือกหนึ่งคือการแปลงไปIterable
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
มากกว่าIterator
... )
สำหรับJava 8คุณสามารถใช้ได้
public static int getIteratorSize(Iterator iterator){
AtomicInteger count = new AtomicInteger(0);
iterator.forEachRemaining(element -> {
count.incrementAndGet();
});
return count.get();
}
ออบเจ็กต์ตัววนซ้ำมีองค์ประกอบจำนวนเท่ากันกับสิ่งที่คอลเลกชันของคุณมีอยู่
List<E> a =...;
Iterator<E> i = a.iterator();
int size = a.size();//Because iterators size is equal to list a's size.
แต่แทนที่จะได้รับขนาดของตัววนซ้ำและวนซ้ำผ่านดัชนี 0 เป็นขนาดนั้นจะเป็นการดีกว่าที่จะวนซ้ำด้วยวิธีการถัดไป ()ของตัววนซ้ำ
a
แต่เพียงอย่างเดียวi
?