จะทำซ้ำผ่าน Set / HashSet โดยไม่มี Iterator ได้อย่างไร?


273

ฉันจะทำซ้ำมากกว่าSet/ HashSetไม่ต่อไปนี้ได้อย่างไร

Iterator iter = set.iterator();
while (iter.hasNext()) {
    System.out.println(iter.next());
}

31
คุณพยายามหลีกเลี่ยงการใช้ตัววนซ้ำจริง ๆ หรือคุณไม่ต้องการเห็นมันในซอร์สโค้ดของคุณหรือไม่?
Jon Skeet

2
คุณสามารถทำให้รหัสสั้นลงและสะอาดขึ้น แต่คุณต้องใช้ Iterator มีเหตุผลที่คุณต้องการหลีกเลี่ยงหรือไม่
Peter Lawrey

5
เพียงเพื่อบันทึกและเป็นคำอธิบายว่าทำไมต้องหลีกเลี่ยงตัวทำซ้ำ: ฉันกำลังเผชิญปัญหาในเกม Android ที่เขียนด้วย Java ตอนนี้ฉันกำลังใช้ HashSet สำหรับจัดเก็บผู้ฟังที่ต้องได้รับการแจ้งเตือนเกี่ยวกับกิจกรรมเป็นประจำ อย่างไรก็ตามการทำซ้ำคอลเลกชันซ้ำ ๆ ทำให้เกิดกิจกรรมการรวบรวมขยะจำนวนมากที่สามารถเป็นภาระของวงเกม และนั่นเป็นเกมที่ไม่ต้องลงเกม Java ฉันจะเขียนส่วนเหล่านี้ใหม่
tiguchi

12
@thecoshman ฉันกำลังพูดเฉพาะจากมุมมองการพัฒนาเกม Java ที่คุณต้องการหลีกเลี่ยง GC ในระหว่างการอัพเดทสถานะเกมปกติที่ค่าใช้จ่ายทั้งหมด Iterator เป็นเพียงวัตถุที่มีประโยชน์ชั่วคราวเนื่องจากคุณไม่สามารถรีเซ็ตพวกมันเป็นจุดเริ่มต้นดังนั้นพวกมันจะได้รับการสร้างขึ้นใหม่ในการเรียกใช้เมธอดการวนซ้ำแต่ละครั้ง (ดูแหล่งที่มาของ ArrayList.java) หากใช้ในวนลูปของเกมสำหรับวนฉากวัตถุและพิจารณาการอัพเดทอย่างน้อย 30 ครั้งต่อวินาทีคุณจะได้รับอย่างน้อย 60 (ฉากมักวนซ้ำสองครั้งต่อรอบ) วัตถุตัววนซ้ำต่อวินาทีในหน่วยความจำที่รอ GC นั่นมีผลกระทบอย่างมากต่อ Android
tiguchi

9
บางทีเราควรเลือกโครงสร้างข้อมูลที่เพียงพอมากขึ้นในกรณีนั้น? ชุดไม่ได้ออกแบบมาเพื่อย้ำอย่างมีประสิทธิภาพ ทำไมไม่ใช้ ArrayList และวนซ้ำกับมาตรฐานสำหรับลูป ไม่มีการสร้างตัววนซ้ำเพิ่มเติมการเข้าถึงเพื่ออ่านนั้นรวดเร็วมาก
stef77

คำตอบ:


492

คุณสามารถใช้Enhanced สำหรับลูป :

Set<String> set = new HashSet<String>();

//populate set

for (String s : set) {
    System.out.println(s);
}

หรือด้วย Java 8:

set.forEach(System.out::println);

65
ฉันเชื่อว่านี่ใช้ตัววนซ้ำเบื้องหลัง
munyengm

22
@munyengm ใช่มันเป็นเช่นนั้น ไม่มีวิธีการวนซ้ำในชุดที่ไม่มีตัววนซ้ำนอกจากเข้าถึงโครงสร้างพื้นฐานที่เก็บข้อมูลผ่านการสะท้อนกลับและจำลองรหัสที่จัดทำโดย Set # iterator ...
assylias

1
ใช้งานได้ แต่ถ้ามันสามารถให้ปัญหาได้แล้วมันไม่ใช่ทางออกสำหรับฉัน ฉันเดาว่าฉันไม่มีทางเลือกฉันต้องใช้ Iterator ขอบคุณสำหรับทุกอย่างอยู่ดี
user1621988

39
@ user1621988 มีปัญหาอะไร ไม่มีปัญหากับรหัสที่ฉันให้ไว้ เป็นเพียงวิธีที่ดีและสะอาดในการวนซ้ำชุดโดยไม่ต้องใช้ตัววนซ้ำอย่างชัดเจน
assylias

90

มีอย่างน้อยหกวิธีเพิ่มเติมในการวนซ้ำชุด ฉันรู้จักสิ่งต่อไปนี้:

วิธีที่ 1

// Obsolete Collection
Enumeration e = new Vector(movies).elements();
while (e.hasMoreElements()) {
  System.out.println(e.nextElement());
}

วิธีที่ 2

for (String movie : movies) {
  System.out.println(movie);
}

วิธีที่ 3

String[] movieArray = movies.toArray(new String[movies.size()]);
for (int i = 0; i < movieArray.length; i++) {
  System.out.println(movieArray[i]);
}

วิธีที่ 4

// Supported in Java 8 and above
movies.stream().forEach((movie) -> {
  System.out.println(movie);
});

วิธีที่ 5

// Supported in Java 8 and above
movies.stream().forEach(movie -> System.out.println(movie));

วิธีที่ 6

// Supported in Java 8 and above
movies.stream().forEach(System.out::println);

นี่คือสิ่งHashSetที่ฉันใช้สำหรับตัวอย่างของฉัน:

Set<String> movies = new HashSet<>();
movies.add("Avatar");
movies.add("The Lord of the Rings");
movies.add("Titanic");

10
สวัสดี @ benny-Neugebauer สำหรับวิธีที่ 4 , วิธีที่ 5 , วิธีที่ 6stream()คุณก็สามารถลบซ้ำซ้อน
Eugene T

5
ไม่ต้องพูดถึงวิธีที่ 4 วิธีที่ 5 และวิธีที่ 6 เหมือนกัน
GustavoCinque

24

การแปลงชุดของคุณเป็นอาร์เรย์ อาจช่วยให้คุณทำซ้ำองค์ประกอบได้:

Object[] array = set.toArray();

for(int i=0; i<array.length; i++)
   Object o = array[i];

45
เพียงบันทึกtoArrayเรียกตัววนซ้ำของชุด
assylias

13

ในการสาธิตให้พิจารณาชุดต่อไปนี้ซึ่งมีออบเจ็กต์ Person ที่แตกต่างกัน:

Set<Person> people = new HashSet<Person>();
people.add(new Person("Tharindu", 10));
people.add(new Person("Martin", 20));
people.add(new Person("Fowler", 30));

Class Model บุคคล

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //TODO - getters,setters ,overridden toString & compareTo methods

}
  1. คำสั่ง for มีรูปแบบที่ออกแบบมาสำหรับการวนซ้ำผ่านคอลเลกชันและอาร์เรย์บางครั้งแบบฟอร์มนี้เรียกว่าการปรับปรุงสำหรับคำสั่งและสามารถใช้เพื่อทำให้ลูปของคุณมีขนาดกะทัดรัดและอ่านง่ายขึ้น
for(Person p:people){
  System.out.println(p.getName());
}
  1. Java 8 - java.lang.Iterable.forEach (ผู้บริโภค)
people.forEach(p -> System.out.println(p.getName()));
default void forEach(Consumer<? super T> action)

Performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception. Unless otherwise specified by the implementing class, actions are performed in the order of iteration (if an iteration order is specified). Exceptions thrown by the action are relayed to the caller. Implementation Requirements:

The default implementation behaves as if: 

for (T t : this)
     action.accept(t);

Parameters: action - The action to be performed for each element

Throws: NullPointerException - if the specified action is null

Since: 1.8


11

ต่อไปนี้เป็นเคล็ดลับเกี่ยวกับวิธีวนซ้ำชุดพร้อมกับการแสดง:

public class IterateSet {

    public static void main(String[] args) {

        //example Set
        Set<String> set = new HashSet<>();

        set.add("Jack");
        set.add("John");
        set.add("Joe");
        set.add("Josh");

        long startTime = System.nanoTime();
        long endTime = System.nanoTime();

        //using iterator
        System.out.println("Using Iterator");
        startTime = System.nanoTime();
        Iterator<String> setIterator = set.iterator();
        while(setIterator.hasNext()){
            System.out.println(setIterator.next());
        }
        endTime = System.nanoTime();
        long durationIterator = (endTime - startTime);


        //using lambda
        System.out.println("Using Lambda");
        startTime = System.nanoTime();
        set.forEach((s) -> System.out.println(s));
        endTime = System.nanoTime();
        long durationLambda = (endTime - startTime);


        //using Stream API
        System.out.println("Using Stream API");
        startTime = System.nanoTime();
        set.stream().forEach((s) -> System.out.println(s));
        endTime = System.nanoTime();
        long durationStreamAPI = (endTime - startTime);


        //using Split Iterator (not recommended)
        System.out.println("Using Split Iterator");
        startTime = System.nanoTime();
        Spliterator<String> splitIterator = set.spliterator();
        splitIterator.forEachRemaining((s) -> System.out.println(s));
        endTime = System.nanoTime();
        long durationSplitIterator = (endTime - startTime);


        //time calculations
        System.out.println("Iterator Duration:" + durationIterator);
        System.out.println("Lamda Duration:" + durationLambda);
        System.out.println("Stream API:" + durationStreamAPI);
        System.out.println("Split Iterator:"+ durationSplitIterator);
    }
}

รหัสอธิบายตนเอง

ผลของระยะเวลาคือ:

Iterator Duration: 495287
Lambda Duration: 50207470
Stream Api:       2427392
Split Iterator:    567294

เราสามารถเห็นการLambdaใช้เวลานานที่สุดในขณะIteratorที่เร็วที่สุด


2

การแจงนับ (?):

Enumeration e = new Vector(set).elements();
while (e.hasMoreElements())
    {
        System.out.println(e.nextElement());
    }

อีกวิธีหนึ่ง (java.util.Collections.enumeration ()):

for (Enumeration e1 = Collections.enumeration(set); e1.hasMoreElements();)
    {
        System.out.println(e1.nextElement());
    }

Java 8:

set.forEach(element -> System.out.println(element));

หรือ

set.stream().forEach((elem) -> {
    System.out.println(elem);
});

0

อย่างไรก็ตามมีคำตอบที่ดีอยู่แล้วสำหรับสิ่งนี้ นี่คือคำตอบของฉัน:

1. set.stream().forEach(System.out::println); // It simply uses stream to display set values
2. set.forEach(System.out::println); // It uses Enhanced forEach to display set values

นอกจากนี้หากชุดนี้เป็นประเภทคลาสที่กำหนดเองเช่น: ลูกค้า

Set<Customer> setCust = new HashSet<>();
    Customer c1 = new Customer(1, "Hena", 20);
    Customer c2 = new Customer(2, "Meena", 24);
    Customer c3 = new Customer(3, "Rahul", 30);

setCust.add(c1);
setCust.add(c2);
setCust.add(c3);
    setCust.forEach((k) -> System.out.println(k.getId()+" "+k.getName()+" "+k.getAge()));

// คลาสลูกค้า:

class Customer{
private int id;
private String name;
private int age;

public Customer(int id,String name,int age){
this.id=id;
this.name=name;
this.age=age;
} // Getter, Setter methods are present.}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.