Saya memiliki larik JavaScript seperti:
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
Bagaimana saya bisa menggabungkan array batin terpisah menjadi seperti:
["$6", "$12", "$25", ...]
javascript
arrays
flatten
Andy
sumber
sumber
reduce
+concat
adalah O ((N ^ 2) / 2) di mana sebagai jawaban yang diterima (hanya satu panggilan keconcat
) akan paling banyak O (N * 2) pada browser yang buruk dan O (N) pada bagus Juga solusi Denys dioptimalkan untuk pertanyaan aktual dan 2x lebih cepat dari yang tunggalconcat
. Untukreduce
orang - orang itu menyenangkan untuk merasa keren menulis kode kecil tetapi misalnya jika array memiliki 1000 elemen satu subarrays semua solusi mengurangi + concat akan melakukan operasi 500500 di mana sebagai concat tunggal atau loop sederhana akan melakukan 1.000 operasi.[].concat(...array)
array.flat(Infinity)
manaInfinity
kedalaman maksimum untuk diratakan.Jawaban:
Anda dapat menggunakan
concat
untuk menggabungkan array:Menggunakan
apply
metodeconcat
hanya akan mengambil parameter kedua sebagai array, sehingga baris terakhir identik dengan ini:Ada juga
Array.prototype.flat()
metode (diperkenalkan dalam ES2019) yang dapat Anda gunakan untuk meratakan array, meskipun hanya tersedia di Node.js dimulai dengan versi 11, dan tidak sama sekali di Internet Explorer .sumber
concat
tidak mengubah larik sumber, sehinggamerged
larik akan tetap kosong setelah panggilan keconcat
. Lebih baik mengatakan sesuatu seperti:merged = merged.concat.apply(merged, arrays);
var merged = [].concat.apply([], arrays);
tampaknya berfungsi dengan baik untuk mendapatkannya di satu baris. sunting: seperti yang ditunjukkan oleh jawaban Nikita.Array.prototype.concat.apply([], arrays)
.var merged = [].concat(...arrays)
Berikut adalah fungsi singkat yang menggunakan beberapa metode array JavaScript yang lebih baru untuk meratakan array n-dimensi.
Pemakaian:
sumber
flat
dalam panggilan pertama ke fungsi anonim diteruskanreduce
. Jika tidak ditentukan, maka panggilan pertama untukreduce
mengikat nilai pertama dari arrayflat
, yang pada akhirnya akan menghasilkan1
terikatflat
pada kedua contoh.1.concat
bukan fungsi.const flatten = (arr) => arr.reduce((flat, next) => flat.concat(next), []);
const flatten = (arr) => arr.reduce((flat, next) => flat.concat(Array.isArray(next) ? flatten(next) : next), []);
Ada metode tersembunyi yang membingungkan, yang membangun array baru tanpa mengubah yang asli:
sumber
[].concat([[1],[2,3],[4]]...)
[[1],[2,3],[4]]
sebagai hasilnya. Solusi yang @Nikita berikan benar untuk CoffeeScript dan juga JS.[].concat([1],[2,3],[4],...)
....
adalah kode aktual, tidak beberapa titik elipsis.Ini bisa dilakukan dengan mengurangi fungsi javascript.
Atau, dengan ES2015:
js-biola
Mozilla docs
sumber
[]
dan tidak perlu validasi lebih lanjut.arrays.reduce((flatten, arr) => [...flatten, ...arr])
Ada metode asli baru yang disebut flat untuk melakukan ini dengan tepat.
(Sampai akhir 2019,
flat
sekarang diterbitkan dalam standar ECMA 2019, dancore-js@3
(perpustakaan babel) memasukkannya ke perpustakaan polyfill mereka )sumber
Sebagian besar jawaban di sini tidak bekerja pada array besar (misalnya 200 000 elemen), dan bahkan jika itu, mereka lambat. Jawaban polkovnikov.ph memiliki kinerja terbaik, tetapi tidak berfungsi untuk meratakan.
Ini adalah solusi tercepat, yang juga berfungsi pada array dengan beberapa level sarang :
Contohnya
Array besar
Ini menangani array besar dengan baik. Di komputer saya kode ini membutuhkan sekitar 14 ms untuk dijalankan.
Array bersarang
Ini bekerja dengan array bersarang. Kode ini menghasilkan
[1, 1, 1, 1, 1, 1, 1, 1]
.Array dengan berbagai tingkat sarang
Itu tidak memiliki masalah dengan meratakan array seperti ini.
sumber
RangeError: Maximum call stack size exceeded
). Untuk 20.000 elemen array dibutuhkan 2-5 milidetik.Pembaruan: ternyata solusi ini tidak berfungsi dengan array besar. Jika Anda mencari solusi yang lebih baik, lebih cepat, periksa jawaban ini .
Hanya memperluas
arr
dan meneruskannya sebagai argumenconcat()
, yang menggabungkan semua array menjadi satu. Ini setara dengan[].concat.apply([], arr)
.Anda juga dapat mencoba ini untuk meratakan:
Lihat demo di JSBin .
Referensi untuk elemen ECMAScript 6 yang digunakan dalam jawaban ini:
Catatan sisi: metode suka
find()
dan fungsi panah tidak didukung oleh semua browser, tetapi itu tidak berarti bahwa Anda tidak dapat menggunakan fitur ini sekarang. Cukup gunakan Babel - ini mengubah kode ES6 menjadi ES5.sumber
apply
dengan cara ini, saya menghapus komentar saya dari Anda. Saya masih berpikir menggunakanapply
/ menyebar dengan cara ini adalah saran yang buruk, tetapi karena tidak ada yang peduli ...const flatten = arr => [].concat(...arr)
Anda dapat menggunakan Garis Bawah :
sumber
true
argumen kedua .Prosedur umum berarti kita tidak perlu menulis ulang kompleksitas setiap kali kita perlu memanfaatkan perilaku tertentu.
concatMap
(atauflatMap
) persis apa yang kita butuhkan dalam situasi ini.tinjauan ke masa depan
Dan ya, Anda menebaknya dengan benar, itu hanya meratakan satu tingkat, yang persis bagaimana seharusnya bekerja
Bayangkan beberapa kumpulan data seperti ini
Oke, sekarang katakan kita ingin mencetak daftar yang menunjukkan semua pemain yang akan berpartisipasi dalam
game
...Jika
flatten
prosedur kami juga meratakan susunan bersarang, kami akan berakhir dengan hasil sampah ini ...berguling dalam, sayang
Itu bukan untuk mengatakan kadang-kadang Anda tidak ingin meratakan array bersarang, - hanya itu yang seharusnya tidak menjadi perilaku default.
Kita dapat membuat
deepFlatten
prosedur dengan mudah ...Sana. Sekarang Anda memiliki alat untuk setiap pekerjaan - satu untuk meremas satu tingkat sarang
flatten
,, dan satu untuk melenyapkan semua sarangdeepFlatten
.Mungkin Anda bisa menyebutnya
obliterate
ataunuke
jika Anda tidak suka namanyadeepFlatten
.Jangan beralih dua kali!
Tentu saja implementasi di atas pintar dan ringkas, tetapi menggunakan
.map
diikuti oleh panggilan untuk.reduce
berarti kita benar-benar melakukan lebih banyak iterasi daripada yang diperlukanMenggunakan kombinator terpercaya saya menelepon
mapReduce
membantu menjaga iterasi ke minium; dibutuhkan fungsi pemetaanm :: a -> b
, fungsi pereduksir :: (b,a) ->b
dan mengembalikan fungsi pereduksi baru - kombinator ini adalah jantung dari transduser ; jika Anda tertarik, saya sudah menulis jawaban lain tentang merekasumber
concat
itu sendiri tidak meledakkan tumpukan, hanya...
danapply
tidak (bersama dengan array yang sangat besar). Saya tidak melihatnya. Aku hanya merasa tidak enak sekarang.concat
dalam Javascript memiliki arti yang berbeda dengan di Haskell. Haskell'sconcat
([[a]] -> [a]
) akan dipanggilflatten
dalam Javascript dan diimplementasikan sebagaifoldr (++) []
(Javascript:foldr(concat) ([])
asumsi fungsi kari). Javascriptconcat
adalah append aneh ((++)
dalam Haskell), yang dapat menangani keduanya[a] -> [a] -> [a]
dana -> [a] -> [a]
.flatMap
, karena itulah tepatnyaconcatMap
:bind
Contoh darilist
monad.concatpMap
diimplementasikan sebagaifoldr ((++) . f) []
. Diterjemahkan ke dalam Javascript:const flatMap = f => foldr(comp(concat) (f)) ([])
. Ini tentu saja mirip dengan implementasi Anda tanpacomp
.Sebuah solusi untuk kasus yang lebih umum, ketika Anda mungkin memiliki beberapa elemen non-array di array Anda.
sumber
Object.defineProperty(Array.prototype,'flatten',{value:function(r){for(var a=this,i=0,r=r||[];i<a.length;++i)if(a[i]!=null)a[i] instanceof Array?a[i].flatten(r):r.push(a[i]);return r}});
flattenArrayOfArrays (arr, 10)
atau iniflattenArrayOfArrays(arr, [1,[3]]);
- argumen kedua ditambahkan ke output.r
,, akan benar-benar menyatukan hasil dari rekursi.Untuk meratakan array array elemen tunggal, Anda tidak perlu mengimpor perpustakaan, loop sederhana adalah solusi paling sederhana dan paling efisien :
Untuk downvoters: harap baca pertanyaannya, jangan downvote karena tidak sesuai dengan masalah Anda yang sangat berbeda. Solusi ini adalah yang tercepat dan paling sederhana untuk pertanyaan yang diajukan.
sumber
['foo', ['bar']]
ke['f', 'bar']
.Bagaimana dengan menggunakan
reduce(callback[, initialValue])
metodeJavaScript 1.8
Akan melakukan pekerjaan itu.
sumber
[[1], [2,3]].reduce( (a,b) => a.concat(b), [] )
lebih seksi.[[1], [2,3]].reduce( (a,b) => a.concat(b))
Solusi ECMAScript 6 lain dalam gaya fungsional:
Deklarasikan fungsi:
dan gunakan:
Pertimbangkan juga fungsi asli Array.prototype.flat () (proposal untuk ES6) yang tersedia di rilis terbaru browser modern. Terima kasih kepada @ (Константин Ван) dan @ (Mark Amery) yang menyebutkannya di komentar.
The
flat
fungsi memiliki satu parameter, menentukan kedalaman diharapkan array bersarang, yang sama1
secara default.sumber
RangeError: Maximum call stack size exceeded
sumber
Harap dicatat: Ketika
Function.prototype.apply
([].concat.apply([], arrays)
) atau operator penyebaran ([].concat(...arrays)
) digunakan untuk meratakan array, keduanya dapat menyebabkan stack overflow untuk array besar, karena setiap argumen dari suatu fungsi disimpan pada stack.Berikut ini adalah implementasi stack-safe dengan gaya fungsional yang menimbang persyaratan yang paling penting terhadap satu sama lain:
Segera setelah Anda terbiasa dengan fungsi panah kecil dalam bentuk kari, komposisi fungsi dan fungsi urutan lebih tinggi, kode ini berbunyi seperti prosa. Pemrograman kemudian hanya terdiri dari menyusun blok bangunan kecil yang selalu berfungsi seperti yang diharapkan, karena mereka tidak mengandung efek samping.
sumber
const flatten = (arr) => arr.reduce((a, b) => a.concat(b), []);
menghemat sampah visual dan penjelasan kepada rekan tim Anda mengapa Anda membutuhkan 3 fungsi tambahan dan beberapa panggilan fungsi juga.ES6 One Line Ratakan
Lihat Lodash rata , garis bawah rata (dangkal
true
)atau
Diuji dengan
ES6 One Line Deep Flatten
Lihat meratakan lodash , garis bawah rata
Diuji dengan
sumber
Array.prototype.concat.apply([], arr)
karena Anda membuat array tambahan hanya untuk mendapatkanconcat
fungsi. Runtimes mungkin atau mungkin tidak mengoptimalkannya ketika mereka menjalankannya, tetapi mengakses fungsi pada prototipe tidak terlihat lebih buruk daripada ini sudah dalam hal apapun.Anda dapat menggunakannya
Array.flat()
denganInfinity
untuk kedalaman array bersarang.periksa di sini untuk kompatibilitas browser
sumber
Pendekatan Haskellesque
sumber
Cara ES6:
Cara ES5 untuk
flatten
fungsi dengan fallback ES3 untuk array bertingkat N-kali:sumber
Jika Anda hanya memiliki array dengan 1 elemen string:
akan melakukan pekerjaan itu. Bt yang secara spesifik cocok dengan contoh kode Anda.
sumber
['$4', ["$6"], ["$12"], ["$25"], ["$25", "$33", ['$45']]].join(',').split(',')
[1,4, [45, 't', ['e3', 6]]].toString().split(',')
---- atau -----[1,4, [45, 't', ['e3', 6], false]].toString().split(',')
(Saya hanya menulis ini sebagai jawaban terpisah, berdasarkan komentar dari @danhbear.)
sumber
Saya merekomendasikan fungsi generator hemat ruang :
Jika diinginkan, buat array nilai rata sebagai berikut:
sumber
...
untuk beralih melalui generator.Saya lebih suka mengubah seluruh array, apa adanya, menjadi string, tetapi tidak seperti jawaban lain, akan melakukannya dengan menggunakan
JSON.stringify
dan tidak menggunakantoString()
metode, yang menghasilkan hasil yang tidak diinginkan.Dengan
JSON.stringify
output itu, yang tersisa hanyalah menghapus semua tanda kurung, membungkus hasilnya dengan tanda tanda mulai & mengakhiri lagi, dan menyajikan hasilJSON.parse
yang mengembalikan string ke "hidup".sumber
["345", "2", "3,4", "2"]
alih-alih memisahkan masing-masing nilai-nilai untuk memisahkan indeks"3,4"
.Anda juga dapat mencoba
Array.Flat()
metode baru . Ini bekerja dengan cara berikut:Itu
flat()
Metode menciptakan sebuah array baru dengan semua elemen sub-array bersambung ke dalamnya secara rekursif hingga 1 lapisan kedalaman (yaitu array di dalam array)Jika Anda juga ingin meratakan array 3 dimensi atau bahkan lebih tinggi, Anda cukup memanggil metode flat beberapa kali. Misalnya (3 dimensi):
Hati-hati!
Array.Flat()
Metode ini relatif baru. Browser lama seperti mis. Mungkin belum menerapkan metode. Jika Anda ingin kode Anda berfungsi pada semua browser, Anda mungkin harus mengubah JS Anda ke versi yang lebih lama. Periksa MD web docs untuk kompatibilitas browser saat ini.sumber
Infinity
argumen. Seperti ini:arr.flat(Infinity)
Menggunakan operator spread:
sumber
Itu tidak sulit, hanya mengulangi array dan menggabungkannya:
sumber
Sepertinya ini terlihat seperti pekerjaan untuk REKURSI!
Kode:
Pemakaian:
sumber
flatten(new Array(15000).fill([1]))
melemparUncaught RangeError: Maximum call stack size exceeded
dan membekukan devTools saya selama 10 detikSaya telah melakukannya menggunakan rekursi dan penutupan
sumber
Saya bermain-main dengan Generator ES6 tempo hari dan menulis inti ini . Yang mengandung...
Pada dasarnya saya membuat generator yang loop atas array input asli, jika menemukan array menggunakan operator hasil * dalam kombinasi dengan rekursi untuk terus meratakan array internal. Jika item tersebut bukan array, ia hanya menghasilkan item tunggal. Kemudian menggunakan operator Spread ES6 (alias operator percikan) saya meratakan generator menjadi contoh array baru.
Saya belum menguji kinerja ini, tapi saya pikir ini adalah contoh sederhana yang bagus untuk menggunakan generator dan operator hasil *.
Tapi sekali lagi, saya hanya bermain-main jadi saya yakin ada lebih banyak cara untuk melakukan ini.
sumber
hanya solusi terbaik tanpa lodash
sumber