Come scorrere su un Set / HashSet senza Iteratore?


273

Come posso iterare su un Set/ HashSetsenza quanto segue?

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

31
Stai davvero cercando di evitare l'uso di un iteratore o semplicemente non vuoi vederlo nel tuo codice sorgente ?
Jon Skeet,

2
Puoi rendere il codice più breve e più pulito, ma devi usare un Iteratore. C'è un motivo per cui vuoi evitarlo?
Peter Lawrey,

5
Solo per la cronaca e come spiegazione del perché evitare l'iteratore: attualmente sto affrontando quel problema in un gioco Android scritto in Java. In questo momento sto usando un HashSet per archiviare i listener che devono essere regolarmente informati sugli eventi. Tuttavia, ripetendo ripetutamente le raccolte provoca pesanti attività di raccolta rifiuti che possono gravare sul ciclo di gioco. E questo è un no-go in un gioco Java. Ho intenzione di riscrivere queste parti.
Tiguchi,

12
@thecoshman Sto parlando solo dal punto di vista dello sviluppo di un gioco Java in cui vuoi evitare GC durante i regolari aggiornamenti dello stato del gioco a tutti i costi. Gli iteratori sono solo oggetti temporaneamente utili poiché non è possibile reimpostarli all'inizio, pertanto vengono ricreati ad ogni chiamata del metodo di iterazione (vedere la fonte ArrayList.java per esempio). Se utilizzato in un loop di gioco per iterare oggetti scena e considerando almeno 30 aggiornamenti al secondo, si ottengono almeno 60 (scena viene ripetuta due volte per ciclo) oggetti iteratori al secondo in memoria in attesa di GC. Questo ha un grande impatto su Android.
Tiguchi,

9
Forse si dovrebbe scegliere una struttura di dati più adeguata in quel caso? Un set non è progettato per iterare in modo efficiente. Perché non usare un ArrayList e iterare su di esso con un ciclo for standard? Non vengono creati iteratori aggiuntivi, l'accesso in lettura è molto veloce.
stef77,

Risposte:


492

È possibile utilizzare un ciclo for avanzato :

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

//populate set

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

O con Java 8:

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

65
Credo che questo usi un iteratore dietro le quinte.
Munyengm,

22
@munyengm Sì. Non c'è modo di iterare su un set senza un iteratore, a parte l'accesso alla struttura sottostante che contiene i dati attraverso la riflessione e la replica del codice fornito da Set # iteratore ...
assylias,

1
Funziona, ma se potrebbe dare problemi, non è la soluzione per me. Immagino di non avere scelta, devo usare Iterator. Grazie comunque a tutti.
user1621988,

39
@ user1621988 Quali problemi? Non ci sono problemi con il codice che ho fornito. Fornisce solo un modo semplice e pulito per scorrere su un set senza dover usare esplicitamente un iteratore.
Assylias,

90

Esistono almeno sei modi aggiuntivi per scorrere su un set. Mi sono conosciuti:

Metodo 1

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

Metodo 2

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

Metodo 3

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

Metodo 4

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

Metodo 5

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

Metodo 6

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

Questo è quello HashSetche ho usato per i miei esempi:

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

10
Ciao @ benny-neugebauer Per Metodo 4 , Metodo 5 , Metodo 6 puoi semplicemente rimuovere ridondanti stream().
Eugene T,

5
Per non parlare del fatto che il Metodo 4, il Metodo 5 e il Metodo 6 sono gli stessi.
GustavoCinque,

24

La conversione del set in un array può anche aiutarti a ripetere gli elementi:

Object[] array = set.toArray();

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

45
Solo per la cronaca, toArraychiama l'iteratore del set.
Assylias,

13

Per dimostrare, considera il seguente set, che contiene diversi oggetti 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));

Classe modello persona

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. L'istruzione for ha un modulo progettato per l'iterazione attraverso le raccolte e le matrici. Questo modulo viene talvolta definito come l'istruzione migliorata per e può essere utilizzato per rendere i loop più compatti e facili da leggere.
for(Person p:people){
  System.out.println(p.getName());
}
  1. Java 8 - java.lang.Iterable.forEach (Consumatore)
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

È possibile utilizzare il funzionamento funzionale per un codice più accurato

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

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

La chiamata richiede API 24
djdance il

11

Ecco alcuni suggerimenti su come iterare un Set insieme alle loro esibizioni:

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

Il codice si spiega da sé.

Il risultato delle durate sono:

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

Possiamo vedere il Lambdatempo più lungo mentre Iteratorè il più veloce.


2

Enumerazione(?):

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

Un altro modo (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));

o

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

0

Tuttavia ci sono già ottime risposte disponibili per questo. Ecco la mia risposta:

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

Inoltre, se questo set è di tipo di classe personalizzato, ad esempio: cliente.

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

// Classe cliente:

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.}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.