Benvenuti in un mondo con Java 8!
Mi ci è voluto solo tutta la notte senza dormire per imparare che cosa era necessario per scrivere questa linea di codice sconvolgente. Sono sicuro che sia già là fuori da qualche parte ma non riuscivo a trovarlo. Quindi sto condividendo le mie ore e ore di ricerca, mi diverto. Woot!
Assumendo:
ArrayList<ArrayList<String>> mainList = new ArrayList<ArrayList<String>>();
// populate this list here
(O, meglio, in Java 8:
ArrayList<ArrayList<String>> mainList = new ArrayList();
//Populate
)
Poi tutto quello che serve è:
String[][] stringArray = mainList.stream().map(u -> u.toArray(new String[0])).toArray(String[][]::new);`
Bam! Una linea.
Non sono sicuro di quanto sia veloce rispetto alle altre opzioni. Ma questo è come funziona:
Prendere un flusso del mainList
2D ArrayList. Questo flusso è un po 'come un Vector collegato a una LinkedList e hanno avuto un bambino.E quel ragazzo, più tardi nella vita, si è schiacciato su un po 'di NZT-48. Io divago; mainList.stream()
restituisce un flusso di elementi ArrayList<String>
. O anche in un linguaggio più geeker: mainList.stream()
restituisce un Stream<ArrayList<String>>
, sorta.
Chiama la funzione .map
su quel flusso che restituirà un nuovo flusso con contenuti che corrispondono a un nuovo tipo specificato dai parametri passati in map
. Questa funzione map
coprirà per noi ogni elemento nel nostro stream. Ha una dichiarazione integrata foreach
. Per realizzare questo; la funzione map
accetta un'espressione lambda come parametro. A Lambda expression è come una semplice funzione a linea singola. Quale ha due tipi di dati gettin' Jiggy wit it. Il primo è il tipo di dati nello stream su cui è stato chiamato (mainList.stream()
). Il prossimo tipo è il tipo di dati a cui verrà mappato, che si trova nella metà destra dell'espressione lambda: u -> u.toArray(new String[0])
. Qui u
è un identificatore scelto proprio come quando si utilizza un'istruzione foreach
. Il primo semestre lo dichiara così: u ->
. E come un foreach
, la variabile u
sarà ora ogni elemento nel flusso mentre itera attraverso il flusso. Pertanto, u
è del tipo di dati che gli elementi del flusso originale sono perché esso è. La metà destra dell'espressione Lambda mostra cosa fare con ciascun elemento: u.toArray(new String[0])
. Con i risultati memorizzati nella loro giusta posizione in un nuovo stream. In questo caso lo convertiamo in un String[]
.. perché dopo tutto, questo è un array 2D di String
.. o meglio da questo punto nel codice, un array 1D di String[]
(string array). Tieni presente che lo u
è in definitiva un ArrayList
. Nota: chiamando toArray
da un oggetto ArrayList
verrà creato un nuovo array del tipo passato in esso. Qui passiamo in new String[0]
. Pertanto crea una nuova matrice di tipo String[]
e con lunghezza pari alla lunghezza di ArrayList u
. Quindi riempie questa nuova serie di stringhe con il contenuto dello ArrayList
e lo restituisce. Che lascia l'espressione Lambda e torna a map
. Quindi, map
raccoglie questi array di stringhe e crea un nuovo flusso con essi, ha il tipo associato String[]
e quindi lo restituisce. Pertanto, map
restituisce uno Stream<String[]>
, in questo caso. (Beh, in realtà restituisce un Stream<Object[]>
, che è fonte di confusione e ha bisogno di conversione, vedi sotto)
Quindi abbiamo solo bisogno di chiamare toArray
su quel nuovo flusso di array di stringhe. Ma chiamare toArray
su un Stream<Object[]>
è leggermente diverso dal chiamarlo su un ArrayList<String>
, come abbiamo fatto prima. Qui, dobbiamo usare una cosa che confonde la funzione di riferimento. Prende il tipo da questo: String[][]::new
. La funzione new
ha il tipo String[][]
. Fondamentalmente, poiché la funzione è chiamata perArray, sarà sempre un []
di qualche tipo. Nel nostro caso, dato che i dati all'interno erano ancora un altro array, aggiungiamo semplicemente un altro []
. Non sono sicuro del motivo per cui la NZT-48 non ha funzionato su questo. Mi sarei aspettato che una chiamata predefinita a toArray()
sarebbe stata sufficiente, visto che è un flusso e tutto. Un flusso che è specificamente Stream<String[]>
. Qualcuno sa perché lorestituisce effettivamente un Stream<Object[]>
e non un flusso del tipo restituito dall'espressione Lambda all'interno?
Ora che abbiamo il toArray
dal nostro stream mainList
che funziona correttamente.Possiamo solo il dump in una variabile locale abbastanza facile: String[][] stringArray = mainList.stream...
Convert 2D ArrayList di interi a matrice 2D di int primitivi
Ora, so che alcuni di voi sono là fuori corso. "Questo non funziona per ints!" Come è stato il mio caso. Funziona comunque per "Ents", vedi sopra. Ma, se si desidera una matrice 2D primitiva int
da un 2D ArrayList
di Integer
(ad esempio ArrayList<ArrayList<Integer>>
). Devi cambiare attorno alla mappatura di mezzo [terra]. Tieni presente che le liste di array non possono avere tipi primitivi. Pertanto non è possibile chiamare toArray
su ArrayList<Integer>
e aspettarsi di ottenere uno int[]
. Dovrai mapparlo di nuovo ... di nuovo.
int[][] intArray = mainList.stream().map( u -> u.stream().mapToInt(i->i).toArray() ).toArray(int[][]::new);
Ho provato a spaziarlo per la leggibilità. Ma qui puoi vedere che dobbiamo ripetere lo stesso intero processo di mappatura. Questa volta non possiamo semplicemente chiamare toArray
su ArrayList u
; come con l'esempio precedente. Qui stiamo chiamando toArray
su un Stream
non uno ArrayList
. Quindi per qualche ragione non dobbiamo passare un "tipo", penso che stia prendendo steroidi cerebrali. Pertanto, possiamo prendere l'opzione predefinita; dove ci vuole un colpo di quel NZT-48 e capisce l'ovvio per noi questa [corsa] tempo. Non sono sicuro del motivo per cui non è stato possibile farlo nell'esempio sopra. Oh, giusto ... Le liste di array non accettano NZT-48 come fanno gli Stream. Aspetta ... di cosa sto parlando?
Annnyhoow, perché i flussi sono così intelligenti. Come Sheldon, abbiamo bisogno di un protocollo completamente nuovo per gestirli. L'intelligenza apparentemente avanzata non sempre significa facile da gestire. Pertanto, questo nuovo mapToInt
è necessario per creare un nuovo che possiamo usare più intelligente toArray
. E l'espressione lambda i->i
in mapToInt
è un semplice annullamento automatico di Integer
a int
, utilizzando l'auto-unboxing implicito che consente int = Integer
. Che, ora, sembra una sciocchezza da fare, come se l'intelligenza avesse i suoi limiti. Durante la mia avventura, ho imparato tutto questo: ho effettivamente provato a usare mapToInt(null)
perché mi aspettavo un comportamento predefinito. Non un argomento !! (tosse Sheldon tosse) allora io dico nel mio miglior ragazza accento Husker valle, "Dopotutto, è chiamato mapToInt
, direi che, come, l'84% del tempo (42 x2) sarà, come, passato i->i
da, come, tutti, così come, omgawd! " Inutile dire che mi sento un po '... come ... this guy. Non so perché non funziona in questo modo!
Beh, sono gli occhi rossi e mezzo delirante e mezzo addormentato. Probabilmente ho fatto degli errori; per favore li troll, così posso sistemarli e farmi sapere se c'è un modo ancora migliore!
PT
Cosa se ho ArrayList e voglio convertirlo in un 2D array? –
shridatt
scusate, questo mi è sfuggito, forse ora lo avete capito ... In ogni caso, è semplicemente 'String [] [] array2D = new String [arrayList.size()] []; per (int i = 0; i