รับIterator<Element>
แล้วเราจะแปลงIterator
ให้เป็นArrayList<Element>
(หรือList<Element>
) ในที่ดีที่สุดและเร็วที่สุดในทางที่เป็นไปเพื่อให้เราสามารถใช้ArrayList
'การดำเนินงานเกี่ยวกับมันเช่นget(index)
, add(element)
ฯลฯ
รับIterator<Element>
แล้วเราจะแปลงIterator
ให้เป็นArrayList<Element>
(หรือList<Element>
) ในที่ดีที่สุดและเร็วที่สุดในทางที่เป็นไปเพื่อให้เราสามารถใช้ArrayList
'การดำเนินงานเกี่ยวกับมันเช่นget(index)
, add(element)
ฯลฯ
คำตอบ:
ควรใช้ห้องสมุดอย่างGuava :
import com.google.common.collect.Lists;
Iterator<Element> myIterator = ... //some iterator
List<Element> myList = Lists.newArrayList(myIterator);
อีกตัวอย่างหนึ่งของฝรั่ง:
ImmutableList.copyOf(myIterator);
หรือคอลเล็กชัน Apache Commons :
import org.apache.commons.collections.IteratorUtils;
Iterator<Element> myIterator = ...//some iterator
List<Element> myList = IteratorUtils.toList(myIterator);
ใน Java 8 คุณสามารถใช้forEachRemaining
วิธีการใหม่ที่ถูกเพิ่มเข้ากับIterator
อินเทอร์เฟซ:
List<Element> list = new ArrayList<>();
iterator.forEachRemaining(list::add);
::
อะไร ชื่ออะไร ดูเหมือนว่าการอ้างอิงโดยตรงไปยัง list.add (); และดูเหมือนว่าบางสิ่งใหม่ java8; และขอบคุณ! :)
::
ไวยากรณ์ใหม่ใน Java 8 และหมายถึง "การอ้างอิงเมธอด" ซึ่งเป็นรูปแบบย่อของแลมบ์ดา ดูที่นี่สำหรับข้อมูลเพิ่มเติม: docs.oracle.com/javase/tutorial/java/javaOO/ …
iterator
มาจากไหน มันเป็นสัญลักษณ์ที่ไม่สามารถแก้ไขได้
iterator
ใช้
คุณสามารถคัดลอกตัววนซ้ำไปยังรายการใหม่ดังนี้:
Iterator<String> iter = list.iterator();
List<String> copy = new ArrayList<String>();
while (iter.hasNext())
copy.add(iter.next());
นั่นคือสมมติว่ารายการมีสตริง ไม่มีวิธีที่เร็วกว่าในการสร้างรายการใหม่จากตัววนซ้ำคุณติดอยู่กับการสำรวจด้วยมือและคัดลอกแต่ละองค์ประกอบไปยังรายการใหม่ของประเภทที่เหมาะสม
แก้ไข:
ต่อไปนี้เป็นวิธีทั่วไปสำหรับการคัดลอกตัววนซ้ำไปยังรายการใหม่ด้วยวิธีที่ปลอดภัย
public static <T> List<T> copyIterator(Iterator<T> iter) {
List<T> copy = new ArrayList<T>();
while (iter.hasNext())
copy.add(iter.next());
return copy;
}
ใช้มันแบบนี้:
List<String> list = Arrays.asList("1", "2", "3");
Iterator<String> iter = list.iterator();
List<String> copy = copyIterator(iter);
System.out.println(copy);
> [1, 2, 3]
โปรดทราบว่ามีความแตกต่างระหว่างIterable
และIterator
และ
หากคุณมีIterable
แล้วด้วย Java 8 คุณสามารถใช้วิธีนี้:
Iterable<Element> iterable = createIterable();
List<Element> array = StreamSupport
.stream(iterable.spliterator(), false)
.collect(Collectors.toList());
ที่ผมรู้ว่าCollectors.toList()
จะสร้างArrayList
อินสแตนซ์
ที่จริงแล้วในความคิดของฉันมันก็ดูดีในหนึ่งบรรทัด
ตัวอย่างเช่นหากคุณต้องการกลับมาList<Element>
จากวิธีการบางอย่าง:
return StreamSupport.stream(iter.spliterator(), false).collect(Collectors.toList());
Iterable
iterator
ซุปเปอร์สับสนว่าคุณชื่อของคุณ พวกเขาแตกต่างอย่างสิ้นเชิง
Iterator
กลับไปใช้เพียงครั้งเดียว โดยใช้Iterable
() -> iterator
สิ่งนี้มีประโยชน์ในสถานการณ์เช่นนี้ แต่ขอให้ฉันเครียดสิ่งสำคัญอีกครั้ง: คุณสามารถใช้วิธีนี้เฉพาะเมื่อยอมรับการใช้ครั้งเดียว Iterable
เท่านั้น การโทรiterable.iterator()
มากกว่าหนึ่งครั้งจะให้ผลลัพธ์ที่ไม่คาดคิด คำตอบข้างต้นจะกลายเป็นIterator<Element> iterator = createIterator();
List<Element> array = StreamSupport.stream(((Iterable<Element>) () -> iterable).spliterator(), false).collect(toList());
นอกจากนี้คุณยังสามารถใช้IteratorUtils
จาก Apache คอมมอนส์คอลเลกชันแม้ว่ามันจะไม่สนับสนุน generics:
List list = IteratorUtils.toList(iterator);
วิธีแก้ปัญหาที่ค่อนข้างกระชับกับ Java 8 ธรรมดาโดยใช้java.util.stream
:
public static <T> ArrayList<T> toArrayList(final Iterator<T> iterator) {
return StreamSupport
.stream(
Spliterators
.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
.collect(
Collectors.toCollection(ArrayList::new)
);
}
iterator.forEachRemaining( list::add )
ใหม่ใน Java 8 มีความกระชับมากขึ้น ผลักดันเข้าสู่ตัวแปรรายการCollector
ไม่ได้ปรับปรุง readibility ในกรณีนี้เพราะมันจะต้องมีการสนับสนุนจากและStream
Spliterator
List result = new ArrayList();
while (i.hasNext()){
result.add(i.next());
}
ลอง StickyList
จากCactoos :
List<String> list = new StickyList<>(iterable);
คำเตือน: ฉันเป็นหนึ่งในนักพัฒนา
Iterable
! =Iterator
นี่คือหนึ่งในสายการบินที่ใช้ Streams
Iterator<?> iterator = ...
List<?> list = StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false)
.collect(Collectors.toList());
ฉันแค่ต้องการชี้ให้เห็นทางออกที่ชัดเจนที่ดูเหมือนจะไม่ทำงาน:
รายการรายการ = Stream.generate (ตัววนซ้ำ :: ถัดไป) .collect (Collectors.toList ());
นั่นเป็นเพราะStream#generate(Supplier<T>)
สามารถสร้างกระแสข้อมูลที่ไม่มีที่สิ้นสุดเท่านั้นมันไม่ได้คาดหวังว่าอาร์กิวเมนต์จะโยนNoSuchElementException
(นั่นคือสิ่งที่Iterator#next()
จะทำในท้ายที่สุด)
คำตอบของ xehpukควรใช้แทนหาก Iterator → Stream → List ทางเป็นทางเลือกของคุณ
ใช้ google ฝรั่ง !
Iterable<String> fieldsIterable = ...
List<String> fields = Lists.newArrayList(fieldsIterable);
++
ที่นี่ในกรณีนี้ถ้าคุณต้องการวิธีที่เร็วที่สุดที่เป็นไปได้แล้วfor loop
จะดีกว่า
ตัววนซ้ำในขนาดตัวอย่างของการ10,000 runs
ทำ40 ms
หน้าที่เป็นที่สำหรับการวนซ้ำ2 ms
ArrayList<String> alist = new ArrayList<String>();
long start, end;
for (int i = 0; i < 1000000; i++) {
alist.add(String.valueOf(i));
}
ListIterator<String> it = alist.listIterator();
start = System.currentTimeMillis();
while (it.hasNext()) {
String s = it.next();
}
end = System.currentTimeMillis();
System.out.println("Iterator start: " + start + ", end: " + end + ", delta: "
+ (end - start));
start = System.currentTimeMillis();
int ixx = 0;
for (int i = 0; i < 100000; i++) {
String s = alist.get(i);
}
System.out.println(ixx);
end = System.currentTimeMillis();
System.out.println("for loop start: " + start + ", end: " + end + ", delta: "
+ (end - start));
นั่นคือสมมติว่ารายการมีสตริง
for
ห่วงและการเข้าถึงองค์ประกอบของรายการที่มีget(i)
จะเร็วกว่าการใช้ iterator ... แต่นั่นไม่ใช่สิ่งที่ OP ก็ถามเขากล่าวถึงเฉพาะที่iteratorจะได้รับเป็น input
get(int)
ลูปคุณจะดูที่ 100k ของ 1m รายการเท่านั้น หากคุณเปลี่ยนลูปนั้นเป็นit.size()
คุณจะเห็นว่า 2 วิธีนี้ใกล้เคียงกับความเร็วเดียวกัน โดยทั่วไปการทดสอบความเร็วจาวาประเภทนี้จะให้ข้อมูลประสิทธิภาพการทำงานในชีวิตจริงที่ จำกัด และควรดูด้วยความสงสัย