Làm cách nào để lặp lại một Set / Hashset mà không cần Iterator?


272

Làm thế nào tôi có thể lặp lại qua một Set/ HashSetkhông có sau đây?

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

31
Bạn có thực sự đang cố gắng tránh việc sử dụng một trình vòng lặp, hoặc bạn chỉ không muốn nhìn thấy nó trong mã nguồn của mình ?
Jon Skeet

2
Bạn có thể làm cho mã ngắn hơn và sạch hơn, nhưng bạn phải sử dụng Iterator. Có một lý do bạn muốn tránh nó?
Peter Lawrey

5
Chỉ để ghi lại và giải thích lý do tại sao nên tránh trình lặp: Tôi hiện đang phải đối mặt với vấn đề đó trong một trò chơi Android được viết bằng Java. Ngay bây giờ tôi đang sử dụng Hashset để lưu trữ các trình nghe cần được thông báo thường xuyên về các sự kiện. Tuy nhiên, các bộ sưu tập lặp đi lặp lại gây ra hoạt động thu gom rác nặng có thể gây gánh nặng cho vòng lặp trò chơi. Và đó là điều không nên làm trong một trò chơi Java. Tôi sẽ viết lại những phần này.
tiguchi

12
@thecoshman Tôi chỉ nói về quan điểm phát triển trò chơi Java, nơi bạn muốn tránh GC trong các cập nhật trạng thái trò chơi thông thường bằng mọi giá. Các trình vòng lặp chỉ là các đối tượng hữu ích tạm thời vì bạn không thể đặt lại chúng để bắt đầu, do đó chúng được tạo lại trên mỗi lệnh gọi phương thức lặp (ví dụ xem nguồn ArrayList.java). Nếu được sử dụng trong một vòng lặp trò chơi để lặp lại các đối tượng cảnh và xem xét ít nhất 30 cập nhật mỗi giây, bạn sẽ có ít nhất 60 (cảnh thường được lặp lại hai lần mỗi chu kỳ) các đối tượng lặp trong một giây trong bộ nhớ đang chờ đợi GC. Điều đó có tác động lớn đến Android.
tiguchi

9
Có lẽ người ta nên chọn một cấu trúc dữ liệu đầy đủ hơn trong trường hợp đó? Một bộ không được thiết kế để lặp lại hiệu quả. Tại sao không sử dụng một ArrayList và lặp lại nó với một vòng lặp tiêu chuẩn? Không có trình vòng lặp bổ sung nào được tạo, truy cập đọc rất nhanh.
stef77

Câu trả lời:


491

Bạn có thể sử dụng vòng lặp nâng cao :

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

//populate set

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

Hoặc với Java 8:

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

65
Tôi tin rằng điều này sử dụng một iterator đằng sau hậu trường.
munyengm

22
@munyengm Đúng vậy. Không có cách nào để lặp lại một tập hợp mà không có trình lặp, ngoài việc truy cập cấu trúc cơ bản chứa dữ liệu thông qua sự phản chiếu và sao chép mã được cung cấp bởi Set # iterator ...
assylias

1
Điều này hoạt động, nhưng nếu nó có thể gây ra vấn đề thì đó không phải là giải pháp cho tôi. Tôi đoán tôi không có lựa chọn, tôi phải sử dụng Iterator. Cảm ơn vì tất cả
dùng1621988

39
@ user1621988 Vấn đề gì? Không có vấn đề với mã tôi cung cấp. Nó chỉ cung cấp một cách tốt đẹp và sạch sẽ để lặp qua một tập hợp mà không cần phải sử dụng một trình lặp rõ ràng.
assylias

90

Có ít nhất sáu cách bổ sung để lặp qua một bộ. Những điều sau đây được biết đến với tôi:

Phương pháp 1

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

Phương pháp 2

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

Phương pháp 3

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

Phương pháp 4

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

Phương pháp 5

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

Phương pháp 6

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

Đây là cái HashSetmà tôi đã sử dụng cho các ví dụ của mình:

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

10
Hi @ benny-neugebauer Đối với Phương pháp 4 , Phương pháp 5 , Phương pháp 6, bạn có thể chỉ cần loại bỏ dự phòng stream().
Eugene T

5
Chưa kể rằng Phương pháp 4, Phương pháp 5 và Phương pháp 6 là như nhau.
GustavoCinque

24

Chuyển đổi tập hợp của bạn thành một mảng cũng có thể giúp bạn lặp lại các yếu tố:

Object[] array = set.toArray();

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

45
Chỉ để ghi lại, toArraygọi iterator của tập hợp.
assylias

13

Để chứng minh, hãy xem xét tập hợp sau, chứa các đối tượng Person khác nhau:

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

Lớp người mẫu

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. Câu lệnh for có một biểu mẫu được thiết kế để lặp qua Bộ sưu tập và mảng. Hình thức này đôi khi được gọi là câu lệnh nâng cao và có thể được sử dụng để làm cho các vòng lặp của bạn gọn hơn và dễ đọc hơn.
for(Person p:people){
  System.out.println(p.getName());
}
  1. Java 8 - java.lang.Iterable.forEach (Người tiêu dùng)
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

Bạn có thể sử dụng hoạt động chức năng cho một mã gọn gàng hơn

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

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

Cuộc gọi yêu cầu API 24
djdance

11

Dưới đây là một số mẹo về cách lặp lại một Bộ cùng với màn trình diễn của họ:

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

Các mã là tự giải thích.

Kết quả của thời lượng là:

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

Chúng ta có thể thấy Lambdamất nhiều thời gian nhất trong khi Iteratorlà nhanh nhất.


2

Bảng liệt kê (?):

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

Một cách khác (java.util.Collections.enumutions ()):

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

Java 8:

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

hoặc là

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

0

Tuy nhiên, có những câu trả lời rất tốt đã có sẵn cho việc này. Đây là câu trả lời của tôi:

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

Ngoài ra, nếu Bộ này thuộc loại lớp Tùy chỉnh, ví dụ: Khách hàng.

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()));

// Lớp khách hàng:

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.}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.