2012-04-26 3 views
90

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

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

Qual è il modo migliore per creare uno Iterable<Integer> da esso?

Iterable<Integer> fooBar = convert(foo); 

Note:

Si prega di non rispondere utilizzando loop

Si noti inoltre che

int a[] = {1,2,3}; 
List<Integer> l = Arrays.asList(a); 
(a meno che non si può dare una buona spiegazione di come il compilatore fare qualcosa di intelligente su di loro?)

Non compila nemmeno

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

Controllare anche Why is an array not assignable to Iterable? prima di rispondere.

Inoltre, se si utilizza una libreria (ad esempio, Guava), si prega di spiegare perché questo è il migliore. (Perché da Google non è una risposta completa: P)

Infine, dal momento che sembra esserci un compito a casa, evitare di postare codice di lavoro.

+0

possibile duplicato [Iterator per array] (http://stackoverflow.com/questions/3912765/iterator-for-array) – NPE

+0

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

risposta

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

Anche se è necessario utilizzare un Integer array (non un int array) per far funzionare tutto questo.

per le primitive, utilizzare Guava:

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

Due note: 1) ha 'int', non' Integer' 2) 'List' è già' Iterable' quindi la terza riga non ha senso. – maksimov

+1

ha bisogno di Iterable perché c'è una terza riga. – fmucar

+1

Quindi la seconda riga è inutile allora? ;) – maksimov

33

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."); 
      } 
     }; 
    } 
}; 
+4

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

+0

+1 Faccio qualcosa di simile per creare un 'Iterator ' da un 'String'. Implementare il proprio 'Iterator' sembra l'unico modo per evitare di ripetere inutilmente tutti i valori per convertire dal tipo di oggetto al tipo primitivo (tramite' Ints.asList() 'di Guava, ad esempio), solo per essere in grado di ottenere un 'Iterator' dalla' Lista' che è stata creata. – spaaarky21

+1

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

19

Guava fornisce l'adattatore che si desidera come Int.asList(). C'è un equivalente per ogni tipo primitivo nella classe associata, ad esempio, per Booleansboolean, 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 per usare Arrays.asList non funziona, anche se compilano perché si ottiene un Iterator<int[]> piuttosto che Iterator<Integer>. Quello che succede è che invece di creare una lista supportata dall'array, hai creato un elenco di array di 1 elemento, contenente l'array.

8

Ho avuto lo stesso problema e 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 è di per sé un pigro UnmodifiableIterator ma questo è esattamente quello che mi serviva.

3

Prima di tutto, posso solo convenire 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 un'implementazione statica privata semplice AbstractList nella classe Arrays che fondamentalmente salva il riferimento dell'array dato come campo e simula un elenco sovrascrivendo i metodi necessari.

Se è possibile scegliere tra un tipo primitivo o un tipo Wrapper per l'array, utilizzerei il tipo Wrapper per tali situazioni, ma ovviamente non è sempre utile o necessario. Ci sarebbero solo due possibilità che si può fare:

1) È possibile creare una classe con un metodo statico per ogni array tipo di dati primitivi (boolean, byte, short, int, long, char, float, double restituisce un Iterable< WrapperType > Questi metodi avrebbero usato le classi anonime di Iterator (oltre Iterable.) 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 fa risparmiare memoria (tranne che per la memoria del nuovo creato metodi, anche se l'utilizzo di Arrays.asList() richiederebbe la memoria allo stesso modo)

2) Poiché gli array non hanno metodi (da leggere sul lato collegato) non possono fornire neanche un'istanza Iterator. Se sei davvero troppo pigro per scrivere nuove classi, devi utilizzare un'istanza di una classe già esistente che implementa Iterable perché non c'è altro modo rispetto all'istanziazione di Iterable o di un sottotipo.
L'unico modo per creare un derivato Collection esistente che implementa Iterable consiste nell'utilizzare un ciclo (eccetto che si utilizzano classi anonime come descritto sopra) o si istanzia una classe di implementazione Iterable il cui costruttore consente una matrice di tipi primitivi (perché Object[] non consente gli array con elementi di tipo primitivi) ma, per quanto ne so, l'API Java non ha una classe come questa.

Il motivo per il ciclo può essere spiegato facilmente:
per ogni raccolta necessaria Gli oggetti ei 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 ogni elemento dell'array di tipo primitivo. Ciò significa che se due modi di tre (utilizzando Arrays.asList(T...) o utilizzando una raccolta esistente) richiedono un aggregato di oggetti, è necessario creare per ciascun valore di base della matrice int[] l'oggetto wrapper. Il terzo modo userebbe l'array così com'è e lo userebbe in una classe anonima perché penso sia preferibile a causa delle prestazioni veloci.

C'è anche una terza strategia che utilizza uno Object come argomento per il metodo in cui si desidera utilizzare l'array o Iterable e richiederebbe controlli di tipo per capire quale tipo l'argomento ha, tuttavia non lo consiglierei a tutti di solito è necessario considerare che l'Oggetto non ha sempre il tipo richiesto e che è necessario un codice separato per alcuni casi.

In conclusione, è colpa del sistema di tipo generico problematico di Java che non consente di utilizzare tipi primitivi come tipo generico che consentirebbe di risparmiare molto codice utilizzando semplicemente Arrays.asList(T...). Quindi è necessario programmare per ogni array di tipo primitivo, è necessario un tale metodo (che fondamentalmente non fa differenza per la memoria utilizzata da un programma C++ che creerebbe per ciascun argomento di tipo utilizzato un metodo separato

20

Con Java 8 , si può fare questo.

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

Nel flusso IntSteam java8 può essere inscatolato per lo streaming di interi.

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

penso che la performance è in base alle dimensioni della matrice.

4

È possibile utilizzare IterableOf da Cactoos:

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

Quindi, è possibile trasformarlo in un elenco tramite ListOf:

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

O semplicemente questo:

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