Converti array Java in Iterable


150

Ho una matrice di primitivi, ad esempio per int, int [] foo. Potrebbe essere di piccole dimensioni o no.

int foo[] = {1,2,3,4,5,6,7,8,9,0};

Qual è il modo migliore per crearne uno Iterable<Integer>?

Iterable<Integer> fooBar = convert(foo);

Appunti:

Per favore non rispondere usando i loop (a meno che tu non possa dare una buona spiegazione su come il compilatore fa qualcosa di intelligente su di loro?)

Si noti anche che

int a[] = {1,2,3};
List<Integer> l = Arrays.asList(a);

Non compilerà nemmeno

Type mismatch: cannot convert from List<int[]> to List<Integer>

Controlla anche Perché un array non è assegnabile a Iterable? prima di rispondere.

Inoltre, se usi qualche libreria (ad esempio, Guava), spiega perché questo è il migliore. (Perché è di Google non è una risposta completa: P)

Infine, dal momento che sembra esserci un compito a riguardo, evita di pubblicare codice per i compiti.


possibile duplicato di Iterator per array
NPE,

Aggiungili a una LinkedList, quindi restituisci l'iteratore di quel set.

Risposte:


117
Integer foo[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

List<Integer> list = Arrays.asList(foo);
// or
Iterable<Integer> iterable = Arrays.asList(foo);

Sebbene sia necessario utilizzare un Integerarray (non un intarray) per farlo funzionare.

Per le primitive, puoi usare la guava:

Iterable<Integer> fooBar = Ints.asList(foo);
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>15.0</version>
    <type>jar</type>
</dependency>

Per Java8: (dalla risposta di Jin Kwon)

final int[] arr = {1, 2, 3};
final PrimitiveIterator.OfInt i1 = Arrays.stream(arr).iterator();
final PrimitiveIterator.OfInt i2 = IntStream.of(arr).iterator();
final Iterator<Integer> i3 = IntStream.of(arr).boxed().iterator();

10
Due note: 1) ha int, non Integer2) Listè già Iterablecosì la terza riga è inutile.
Maksimov,

1
ha bisogno di Iterable per quello che esiste la terza linea.
fmucar,

5
La seconda e la terza riga sono opzioni che direi :)
fmucar,

1
Questo non fa parte dei compiti a casa, stavo solo cercando di evitare la duplicazione del codice per una funzione di debug che elabora il contenuto di un array o di un elenco ... Mentre mi guardavo intorno, ho effettivamente trovato Arrays.asList (..); ma almeno Eclipse sembra pensare che non farà ciò che voglio (es., Inferma il risultato di Arrays.asList (pippo) come un Elenco <int []>, non Elenco <Integer> ...) L'ho trovato abbastanza interessante per un domanda ... (-Rompendo il commento in parte causa dei limiti-)
ntg

1
In generale si potrebbe pensare a molti modi per farlo, ma mi chiedevo quale sia il MIGLIORE (ad esempio un loop sarebbe più lento rispetto a ... {beh, il problema è che non riesco a pensare a niente !: )}) Controlla anche stackoverflow.com/questions/1160081/… per una discussione sul perché, la mia domanda però non è il perché, ma come e quale tipo di contenitore sarebbe meglio (perché ArrayList? In effetti, potrei immaginare qualche AbstractList wrapper usando Generics .., Probabilmente dipende dalle dimensioni ...)
ntg

44

solo i miei 2 centesimi:

final int a[] = {1,2,3};

java.lang.Iterable<Integer> aIterable=new Iterable<Integer>() {

    public Iterator<Integer> iterator() {
       return new Iterator<Integer>() {
            private int pos=0;

            public boolean hasNext() {
               return a.length>pos;
            }

            public Integer next() {
               return a[pos++];
            }

            public void remove() {
                throw new UnsupportedOperationException("Cannot remove an element of an array.");
            }
        };
    }
};

9
remove () non è necessario in Java 8, perché è un metodo predefinito che genera UnsupportedOperationException. Solo se si desidera fornire un messaggio di spiegazione migliore.
Alex

+1 Faccio qualcosa di simile per creare un Iterator<Character>da a String. L'implementazione del proprio Iteratorsembra l'unico modo per evitare di scorrere inutilmente tutti i valori per convertire dal tipo di oggetto al tipo primitivo ( Ints.asList()ad esempio tramite quello di Guava ), solo per essere in grado di ricavarne uno Iteratorda Listquello creato.
spaaarky21,

2
Hai ragione Alex. I metodi predefiniti sono stati aggiunti a Java 8. Nel 2013 ho aggiunto qui questo antico pezzo di codice.
Joerg Ruethschilling,

29

Con Java 8, puoi farlo.

final int[] arr = {1, 2, 3};
final PrimitiveIterator.OfInt i1 = Arrays.stream(arr).iterator();
final PrimitiveIterator.OfInt i2 = IntStream.of(arr).iterator();
final Iterator<Integer> i3 = IntStream.of(arr).boxed().iterator();

20

Guava fornisce l'adattatore desiderato come Int.asList () . Esiste un equivalente per ciascun tipo primitivo nella classe associata, ad esempio, Booleansper boolean, ecc.

int foo[] = {1,2,3,4,5,6,7,8,9,0};
Iterable<Integer> fooBar = Ints.asList(foo);
for(Integer i : fooBar) {
    System.out.println(i);
}

I suggerimenti di cui sopra Arrays.asListnon funzioneranno, anche se vengono compilati perché si ottiene un Iterator<int[]>anziché Iterator<Integer>. Ciò che accade è che anziché creare un elenco supportato dall'array, è stato creato un elenco di array a 1 elemento, contenente l'array.


solo una nota: il link non funziona più. Link Github: github.com/google/guava/blob/master/guava/src/com/google/common/…
Orangle,

Grazie @Passi, risolto (sembra che non riesca più a trovare un modo supportato da Google per collegarsi a javadoc, quindi mi sono collegato alla fonte che hai fornito).
BeeOnRope,

8

Ho avuto lo stesso problema e l'ho risolto in questo modo:

final YourType[] yourArray = ...;
return new Iterable<YourType>() {
  public Iterator<YourType> iterator() {
     return Iterators.forArray(yourArray);   // Iterators is a Google guava utility
  }
}

L'iteratore stesso è pigro UnmodifiableIteratorma è esattamente quello di cui avevo bisogno.


7

In Java 8 o versioni successive, Iterableviene restituita un'interfaccia funzionale Iterator. Quindi puoi farlo.

int[] array = {1, 2, 3};
Iterable<Integer> iterable = () -> Arrays.stream(array).iterator();
for (int i : iterable)
    System.out.println(i);

->

1
2
3

3

Prima di tutto, posso solo concordare sul fatto che Arrays.asList(T...)è chiaramente la soluzione migliore per i tipi di wrapper o array con tipi di dati non primitivi. Questo metodo chiama un costruttore di una semplice AbstractListimplementazione statica privata nella Arraysclasse che sostanzialmente salva il riferimento dell'array dato come campo e simula un elenco sovrascrivendo i metodi necessari.

Se potessi scegliere tra un tipo primtive o un tipo Wrapper per il tuo array, utilizzerei il tipo Wrapper per tali situazioni, ma ovviamente non è sempre utile o obbligatorio. Ci sarebbero solo due possibilità che puoi fare:

1) Puoi creare una classe con un metodo statico per ogni array di tipi di dati primitivo ( boolean, byte, short, int, long, char, float, doublerestituendo un Iterable<WrapperType >. Questi metodi utilizzerebbero classi anonime di Iterator(oltreIterable) che possono contenere il riferimento dell'argomento del metodo comprendente (ad esempio un int[]) come campo per implementare i metodi.

-> Questo approccio è performante e ti consente di risparmiare memoria (tranne per la memoria dei metodi appena creati, anche se l'utilizzo Arrays.asList()richiederebbe la memoria nello stesso modo)

2) Poiché le matrici non hanno metodi (da leggere a lato hai collegato) non possono neanche fornire Iteratorun'istanza. Se sei davvero troppo pigro per scrivere nuove classi, devi usare un'istanza di una classe già esistente che implementa Iterableperché non c'è altro modo di aggirare l'istanza Iterableo un sottotipo.
L'UNICO modo per creare un'implementazione derivata Collection esistenteIterableconsiste nell'utilizzare un ciclo (tranne per il fatto che si usano classi anonime come descritto sopra) o si crea un'istanza di una Iterableclasse di implementazione il cui costruttore consente una matrice di tipo primitiva (perché Object[]non consente matrici con elementi di tipo primitivi) ma, per quanto ne so, l'API Java non presenta una classe del genere.

La ragione del ciclo può essere spiegata facilmente:
per ogni Collezione hai bisogno di Oggetti e tipi di dati primitivi non sono oggetti. Gli oggetti sono molto più grandi dei tipi primitivi, quindi richiedono dati aggiuntivi che devono essere generati per ciascun elemento dell'array di tipi primitivi. Ciò significa che se due modi di tre (usando Arrays.asList(T...)o usando una Collezione esistente) richiedono un aggregato di oggetti, devi creare per ogni valore primitivo del tuoint[]array l'oggetto wrapper. Il terzo modo sarebbe usare l'array così com'è e usarlo in una classe anonima poiché penso che sia preferibile a causa delle prestazioni veloci.

Esiste anche una terza strategia che utilizza un Objectargomento as per il metodo in cui si desidera utilizzare l'array Iterablee che richiederebbe controlli del tipo per capire quale tipo ha l'argomento, tuttavia non lo consiglio affatto come di solito è necessario considera che l'Oggetto non ha sempre il tipo richiesto e che hai bisogno di codice separato per alcuni casi.

In conclusione, è colpa del problematico sistema di tipo generico Java che non consente di utilizzare tipi primitivi come tipo generico che risparmierebbe molto codice usando semplicementeArrays.asList(T...). Quindi è necessario programmare per ogni array di tipi primitivi, è necessario un tale metodo (che sostanzialmente non fa alcuna differenza per la memoria utilizzata da un programma C ++ che creerebbe per ogni argomento di tipo usato un metodo separato.


3

Puoi usare IterableOfda Cactoos :

Iterable<String> names = new IterableOf<>(
  "Scott Fitzgerald", "Fyodor Dostoyevsky"
);

Quindi, puoi trasformarlo in un elenco usando ListOf:

List<String> names = new ListOf<>(
  new IterableOf<>(
    "Scott Fitzgerald", "Fyodor Dostoyevsky"
  )
);

O semplicemente questo:

List<String> names = new ListOf<>(
  "Scott Fitzgerald", "Fyodor Dostoyevsky"
);

1

Mentre una risposta simile è già stata pubblicata, penso che il motivo per utilizzare il nuovo PrimitiveIterator.OfInt non fosse chiaro. Una buona soluzione è utilizzare Java 8 PrimitiveIterator poiché è specializzato per i tipi di int primitivi (ed evita la penalità extra di boxe / unboxing):

    int[] arr = {1,2,3};
    // If you use Iterator<Integer> here as type then you can't get the actual benefit of being able to use nextInt() later
    PrimitiveIterator.OfInt iterator = Arrays.stream(arr).iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.nextInt());
        // Use nextInt() instead of next() here to avoid extra boxing penalty
    }

Rif: https://doc.bccnsoft.com/docs/jdk8u12-docs/api/java/util/PrimitiveIterator.OfInt.html


-2

In java8 il flusso IntSteam può essere inscatolato come flusso di numeri interi.

public static Iterable<Integer> toIterable(int[] ints) {
    return IntStream.of(ints).boxed().collect(Collectors.toList());
}

Penso che le prestazioni contino in base alle dimensioni dell'array.

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.