Apa cara paling efisien untuk membuat array panjang nol yang diisi secara sewenang-wenang dalam JavaScript?
javascript
arrays
dil
sumber
sumber
let i = 0; Array.from(Array(10), ()=>i++);
Jawaban:
ES6 memperkenalkan
Array.prototype.fill
. Dapat digunakan seperti ini:Tidak yakin apakah itu cepat, tapi saya suka karena pendek dan menggambarkan diri sendiri.
Itu masih tidak di IE ( periksa kompatibilitas ), tetapi ada polyfill yang tersedia .
sumber
new Array(len)
sangat lambat.(arr = []).length = len; arr.fill(0);
adalah tentang solusi tercepat ive terlihat di mana saja ... atau setidaknya terikatarr = Array(n)
dan(arr = []).length = n
berperilaku sesuai dengan spesifikasi. Dalam beberapa implementasi seseorang bisa lebih cepat, tetapi saya tidak berpikir ada perbedaan besar.(arr = []).length = 1000;
terhadaparr = new Array(1000);
kecepatan, ujilah di Chrome dan FF ... prosesnyanew
sangat lambat. Sekarang, untuk panjang array yang lebih kecil .. katakan <50 atau ada sekitar ... makanew Array()
tampaknya berkinerja lebih baik. Tapi ..arr.fill(0)
... semuanya berubah. Sekarang, menggunakannew Array()
lebih cepat dalam banyak kasus kecuali ketika Anda mendapatkan ukuran array> 100000 ... Kemudian Anda dapat mulai melihat kecepatan meningkat lagi. Tetapi jika Anda tidak benar-benar harus mengisinya dengan nol dan dapat menggunakan falisy standar array kosong. Maka(arr = []).length = x
gila cepat dalam kasus pengujian saya sebagian besar waktu.new Array(5).forEach(val => console.log('hi'));
vsnew Array(5).fill(undefined).forEach(val => console.log('hi'));
.Meskipun ini adalah utas lama, saya ingin menambahkan 2 sen ke dalamnya. Tidak yakin seberapa lambat / cepatnya ini, tapi ini adalah kapal cepat. Inilah yang saya lakukan:
Jika saya ingin mengisi sebelumnya dengan nomor:
Jika saya ingin mengisi sebelumnya dengan string:
Jawaban lain telah menyarankan:
tetapi jika Anda ingin 0 (angka) dan bukan "0" (nol di dalam string), Anda dapat melakukan:
sumber
Array.apply(null, new Array(5)).map(...)
? Karena cukup melakukan (new Array (5)). Map (...) tidak akan berfungsi seperti yang diceritakan oleh specnew
) Saat Anda melakukannya,Array(5)
Anda membuat objek yang terlihat seperti ini:{ length: 5, __proto__: Array.prototype }
- cobaconsole.dir( Array(5) )
. Perhatikan bahwa itu tidak memiliki sifat setiap0
,1
,2
, dll Tapi ketika Andaapply
bahwa kepadaArray
konstruktor, itu seperti mengatakanArray(undefined, undefined, undefined, undefined, undefined)
. Dan Anda mendapatkan objek yang agak mirip{ length: 5, 0: undefined, 1: undefined...}
.map
bekerja pada properti0
,,1
dll. itulah sebabnya contoh Anda tidak berfungsi, tetapi ketika Anda menggunakannyaapply
tidak..apply
sebenarnya adalah yang Anda inginkanthis
. Untuk tujuanthis
ini, tidak masalah - kami hanya benar-benar peduli tentang penyebaran "fitur" parameter.apply
- sehingga dapat berupa nilai apa pun. Saya sukanull
karena murah, Anda mungkin tidak ingin menggunakan{}
atau[]
karena Anda akan membuat objek tanpa alasan.Cara yang elegan untuk mengisi array dengan nilai yang dikomputasi
Berikut ini cara lain untuk melakukannya menggunakan ES6 yang sejauh ini belum ada yang disebutkan:
Ini berfungsi dengan melewatkan fungsi peta sebagai parameter kedua
Array.from
.Pada contoh di atas, parameter pertama mengalokasikan array 3 posisi yang diisi dengan nilai
undefined
dan kemudian fungsi lambda memetakan masing-masing dari mereka ke nilai0
.Meskipun
Array(len).fill(0)
lebih pendek, itu tidak berfungsi jika Anda perlu mengisi array dengan melakukan perhitungan terlebih dahulu (saya tahu pertanyaannya tidak menanyakannya, tetapi banyak orang akhirnya mencari di sini) .Misalnya, jika Anda memerlukan array dengan 10 angka acak:
Ini lebih ringkas (dan elegan) daripada yang setara:
Metode ini juga dapat digunakan untuk menghasilkan urutan angka dengan memanfaatkan parameter indeks yang disediakan dalam panggilan balik:
Jawaban bonus: isi array menggunakan String
repeat()
Karena jawaban ini mendapat banyak perhatian, saya juga ingin menunjukkan trik keren ini. Meskipun tidak berguna sebagai jawaban utama saya, akan memperkenalkan
repeat()
metode String masih tidak begitu dikenal, tetapi sangat berguna . Inilah triknya:Keren ya
repeat()
adalah metode yang sangat berguna untuk membuat string yang merupakan pengulangan dari string asli beberapa kali. Setelah itu,split()
buat array untuk kita, yang kemudianmap()
ped ke nilai yang kita inginkan. Hancurkan dalam beberapa langkah:sumber
repeat
triknya jelas tidak diinginkan dalam produksi,Array.from()
baik-baik saja :-)Pendeknya
Solusi tercepat
let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;
Solusi terpendek (praktis) (3x lebih lambat untuk array kecil, sedikit lebih lambat untuk besar (paling lambat di Firefox))
Array(n).fill(0)
Detail
Hari ini 2020.06.09 saya melakukan tes pada macOS High Sierra 10.13.6 pada browser Chrome 83.0, Firefox 77.0, dan Safari 13.1. Saya menguji solusi yang dipilih untuk dua kasus uji
Kesimpulan
new Array(n)+for
(N) adalah solusi tercepat untuk array kecil dan array besar (kecuali Chrome tetapi masih sangat cepat di sana) dan direkomendasikan sebagai solusi lintas-browser yang cepatnew Float32Array(n)
(I) mengembalikan array non-tipikal (mis. Anda tidak dapat memanggilnyapush(..)
) jadi saya tidak membandingkan hasilnya dengan solusi lain - namun solusi ini sekitar 10-20x lebih cepat daripada solusi lain untuk array besar di semua browserfor
(L, M, N, O) cepat untuk array kecilfill
(B, C) cepat di Chrome dan Safari tetapi mengejutkan paling lambat di Firefox untuk array besar. Mereka sedang cepat untuk array kecilArray.apply
(P) melempar kesalahan untuk array besarTampilkan cuplikan kode
Kode dan contoh
Kode di bawah ini menyajikan solusi yang digunakan dalam pengukuran
Tampilkan cuplikan kode
Contoh hasil untuk Chrome
sumber
let a=[]; for(i=n;i--;) a.push(0);
- tetapi 4x lebih lambat darifill(0)
- jadi saya bahkan tidak akan memperbarui penyihir gambar case itu.Metode pengisian ES 6 yang disebutkan telah menangani hal ini dengan baik. Sebagian besar browser desktop modern sudah mendukung metode prototipe Array yang diperlukan hingga saat ini (Chromium, FF, Edge, dan Safari) [ 1 ]. Anda dapat melihat detail di MDN . Contoh penggunaan sederhana adalah
Mengingat dukungan browser saat ini, Anda harus berhati-hati untuk menggunakan ini kecuali Anda yakin audiens Anda menggunakan browser Desktop modern.
sumber
a = Array(10).fill(null).map(() => { return []; });
a = Array(10).fill(0).map( _ => [] );
Catatan ditambahkan Agustus 2013, diperbarui Februari 2015: Jawaban di bawah ini dari 2009 berkaitan dengan
Array
jenis generik JavaScript . Itu tidak berhubungan dengan array yang diketik lebih baru yang didefinisikan dalam ES2015 [dan tersedia sekarang di banyak browser], sepertiInt32Array
dan itu. Perhatikan juga bahwa ES2015 menambahkanfill
metode untuk kedua array dan array yang diketik , yang mungkin merupakan cara paling efisien untuk mengisinya ...Juga, ini dapat membuat perbedaan besar pada beberapa implementasi bagaimana Anda membuat array. Mesin V8 Chrome, khususnya, mencoba menggunakan larik memori yang sangat efisien dan bersebelahan jika dianggap bisa, bergeser ke larik berbasis objek hanya bila diperlukan.
Dengan sebagian besar bahasa, ini akan dialokasikan sebelumnya, lalu isi nol, seperti ini:
Tapi , array JavaScript tidak benar-benar array , mereka adalah kunci / nilai peta seperti semua objek JavaScript lainnya, jadi tidak ada "pra-alokasi" untuk dilakukan (pengaturan panjang tidak mengalokasikan banyak slot untuk diisi), atau apakah ada alasan untuk percaya bahwa manfaat penghitungan mundur ke nol (yang hanya untuk membuat perbandingan dalam loop cepat) tidak kalah dengan menambahkan kunci dalam urutan terbalik ketika implementasi mungkin telah dioptimalkan penanganannya terhadap kunci. terkait dengan array pada teori Anda biasanya akan melakukannya secara berurutan.
Bahkan, Matthew Crumley menunjukkan bahwa menghitung mundur jauh lebih lambat di Firefox daripada menghitung, hasil yang saya dapat konfirmasi - ini adalah bagian arraynya (pengulangan ke nol masih lebih cepat daripada pengulangan ke batas dalam var). Tampaknya menambahkan elemen ke array dalam urutan terbalik adalah operasi lambat di Firefox. Faktanya, hasilnya sedikit berbeda dengan implementasi JavaScript (yang tidak terlalu mengejutkan). Berikut ini adalah halaman pengujian cepat dan kotor (di bawah) untuk implementasi browser (sangat kotor, tidak menghasilkan selama pengujian, jadi berikan umpan balik minimal dan akan bertabrakan dengan batas waktu skrip). Saya sarankan menyegarkan di antara tes; FF (setidaknya) melambat pada tes berulang jika Anda tidak.
Versi yang cukup rumit yang menggunakan concat Array # lebih cepat daripada init langsung pada FF pada suatu tempat antara 1.000 dan 2.000 array elemen. Di mesin V8 Chrome, meskipun, init langsung menang setiap kali ...
Inilah halaman pengujian ( salinan langsung ):
sumber
Secara default
Uint8Array
,Uint16Array
danUint32Array
kelas menyimpan nol sebagai nilainya, jadi Anda tidak perlu teknik pengisian yang rumit, cukup lakukan:semua elemen array
ary
akan menjadi nol secara default.sumber
Array.isArray(ary)
adalahfalse
. Panjangnya juga hanya baca sehingga Anda tidak dapat mendorong item baru ke dalamnya denganary.push
0
sebagai nilai default mereka.Array.from(new Uint8Array(10))
akan menyediakan array normal.Array(n).fill(0)
di Chrome jika yang benar-benar Anda butuhkan adalah JS Array. Jika Anda dapat menggunakan TypedArray, ini jauh lebih cepat daripada.fill(0)
, meskipun, terutama jika Anda dapat menggunakan nilai initializer default sebesar0
. Sepertinya tidak ada konstruktor yang membutuhkan nilai isian dan panjang, seperti yang dimiliki C ++std::vector
. Tampaknya untuk setiap nilai non-nol Anda harus membangun TypedArray yang nol dan kemudian mengisinya. : /Jika Anda menggunakan ES6, Anda dapat menggunakan Array.from () seperti ini:
Memiliki hasil yang sama dengan
Karena
sumber
Perhatikan bahwa
while
biasanya lebih efisien daripadafor-in
,forEach
, dllsumber
i
variabel lokal itu asing?length
dilewatkan oleh nilai sehingga Anda harus dapat menurunkannya secara langsung.arr[i] = value
). Jauh lebih cepat untuk mengulang dari awal hingga akhir dan menggunakannyaarr.push(value)
. Ini menjengkelkan, karena saya lebih suka metode Anda.menggunakan notasi objek
nol diisi? Suka...
diisi dengan 'tidak terdefinisi' ...
notasi obj dengan nol
Sebagai catatan, jika Anda memodifikasi prototipe Array, keduanya
dan
akan memiliki modifikasi prototipe tersebut
Bagaimanapun, saya tidak akan terlalu khawatir dengan efisiensi atau kecepatan operasi ini, ada banyak hal lain yang Anda mungkin akan lakukan yang jauh lebih boros dan mahal daripada menginvestasikan array panjang yang mengandung nol.
sumber
null
dalam array ini -var x = new Array(7);
new Array(7)
tidak tidak membuat sebuah array "diisi dengan undefined". Ini menciptakan array kosong dengan panjang 7.(new Array(10)).fill(0)
.Saya telah menguji semua kombinasi pra-alokasi / bukan pra-alokasi, menghitung naik / turun, dan untuk / sementara loop di IE 6/7/8, Firefox 3.5, Chrome, dan Opera.
Fungsi di bawah ini secara konsisten paling cepat atau sangat dekat di Firefox, Chrome, dan IE8, dan tidak jauh lebih lambat daripada yang tercepat di Opera dan IE 6. Ini juga yang paling sederhana dan paling jelas menurut saya. Saya telah menemukan beberapa browser di mana versi loop sementara sedikit lebih cepat, jadi saya memasukkannya juga untuk referensi.
atau
sumber
var array = []
deklarasi ke bagian pertama dari for loop sebenarnya, dipisahkan oleh hanya koma.length
nilai yang sudah diberikan sehingga tidak terus berubah. Membawa array 1 juta panjang nol dari 40ms ke 8 di mesin saya.for (i = 0, array = []; i < length; ++i) array[i] = val;
.. Lebih sedikit blok? ... bagaimanapun juga ... jika saya mengaturarray.length
array baru ke panjang .. saya sepertinya mendapatkan peningkatan kecepatan 10% -15% lainnya di FF ... di Chrome, sepertinya menggandakan kecepatan ->var i, array = []; array.length = length; while(i < length) array[i++] = val;
(masih lebih cepat jika saya meninggalkannya sebagai sebuahfor
loop ... tetapi init tidak lagi diperlukan, sehinggawhile
tampaknya lebih cepat pada versi ini)Jika Anda perlu membuat banyak array yang diisi nol dengan panjang yang berbeda selama eksekusi kode Anda, cara tercepat yang saya temukan untuk mencapainya adalah dengan membuat array nol sekali , menggunakan salah satu metode yang disebutkan pada topik ini, dari panjang yang Anda tahu tidak akan pernah terlampaui, dan kemudian mengiris array yang diperlukan.
Sebagai contoh (menggunakan fungsi dari jawaban yang dipilih di atas untuk menginisialisasi array), buat array panjang nol yang diisi maxLength , sebagai variabel yang terlihat oleh kode yang membutuhkan zero array:
Sekarang iris array ini setiap kali Anda membutuhkan array panjang yang diisi nol, dibutuhkan Panjang < maxLength :
Saya membuat nol array yang diisi ribuan kali selama eksekusi kode saya, ini mempercepat proses dengan luar biasa.
sumber
sumber
new Array(size+1).join("x").split("x").map(function() { return 0; })
untuk mendapatkan angka aktualnew Array(size+1).join('0').split('').map(Number)
Saya tidak menentang:
disarankan oleh Zertosh, tetapi dalam ekstensi array ES6 baru memungkinkan Anda untuk melakukan ini dengan
fill
metode asli. Sekarang IE edge, Chrome dan FF mendukungnya, tetapi periksa tabel kompatibilitasnew Array(3).fill(0)
akan memberimu[0, 0, 0]
. Anda dapat mengisi array dengan nilai apa saja sepertinew Array(5).fill('abc')
(bahkan objek dan array lainnya).Selain itu, Anda dapat memodifikasi array sebelumnya dengan mengisi:
yang memberi Anda:
[1, 2, 3, 9, 9, 6]
sumber
Cara saya biasanya melakukannya (dan sangat cepat) menggunakan
Uint8Array
. Misalnya, membuat vektor elemen 1M yang diisi nol:Saya adalah pengguna Linux dan selalu bekerja untuk saya, tetapi begitu seorang teman yang menggunakan Mac memiliki beberapa elemen yang tidak nol. Saya pikir mesinnya tidak berfungsi, tetapi masih inilah cara teraman yang kami temukan untuk memperbaikinya:
Diedit
Chrome 25.0.1364.160
Firefox 20.0
Hilang ujian paling penting (setidaknya untuk saya): yang Node.js. Saya menduga itu dekat dengan tolok ukur Chrome.
sumber
Menggunakan lodash atau garis bawah
Atau jika Anda memiliki array yang ada dan Anda ingin array dengan panjang yang sama
sumber
_.range(0, length, 0)
, saya percaya. Lodash tidak termasuk nilai akhirSolusi ES6:
sumber
Pada ECMAScript2016 , ada satu pilihan yang jelas untuk array besar.
Karena jawaban ini masih muncul di dekat bagian atas pencarian Google, inilah jawaban untuk 2017.
Berikut adalah jsbench saat ini dengan beberapa lusin metode populer, termasuk banyak yang diajukan hingga sekarang pada pertanyaan ini. Jika Anda menemukan metode yang lebih baik, tambahkan, garpu, dan bagi.
Saya ingin mencatat bahwa tidak ada cara yang benar-benar efisien untuk membuat panjang nol array diisi sewenang-wenang. Anda dapat mengoptimalkan untuk kecepatan, atau untuk kejelasan dan pemeliharaan - baik dapat dianggap sebagai pilihan yang lebih efisien tergantung pada kebutuhan proyek.
Saat mengoptimalkan kecepatan, Anda ingin: membuat array menggunakan sintaks literal; atur panjangnya, inisialisasi variabel iterasi, dan lakukan iterasi melalui array menggunakan loop sementara. Ini sebuah contoh.
Kemungkinan implementasi lain adalah:
Tapi saya sangat tidak menyarankan untuk menggunakan implantasi kedua ini karena kurang jelas dan tidak memungkinkan Anda untuk mempertahankan pelingkupan blok pada variabel array Anda.
Ini secara signifikan lebih cepat daripada mengisi dengan for loop, dan sekitar 90% lebih cepat daripada metode standar
Tetapi metode pengisian ini masih merupakan pilihan yang paling efisien untuk array yang lebih kecil karena kejelasan, keringkasan dan pemeliharaannya. Perbedaan kinerja kemungkinan tidak akan membunuh Anda kecuali jika Anda membuat banyak array dengan panjang pada urutan ribuan atau lebih.
Beberapa catatan penting lainnya. Sebagian besar panduan gaya merekomendasikan Anda untuk tidak lagi menggunakan
var
tanpa alasan yang sangat khusus saat menggunakan ES6 atau yang lebih baru. Gunakanconst
untuk variabel yang tidak akan didefinisikan ulang danlet
untuk variabel yang akan. The MDN dan Airbnb ini Style Guide adalah tempat yang bagus untuk pergi untuk informasi lebih lanjut tentang praktik terbaik. Pertanyaannya bukan tentang sintaksis, tetapi penting bahwa orang yang baru mengenal JS tahu tentang standar baru ini ketika mencari melalui rim ini dari jawaban lama dan baru.sumber
Untuk membuat Array baru
Untuk menambahkan beberapa nilai di akhir Array yang ada
[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]
Contoh
sumber
Tidak melihat metode ini dalam jawaban, jadi ini dia:
Hasilnya, Anda akan mendapatkan array bernilai nol dengan panjang 200:
Saya tidak yakin tentang kinerja kode ini, tetapi seharusnya tidak menjadi masalah jika Anda menggunakannya untuk array yang relatif kecil.
sumber
sumber
Ini
concat
versi jauh lebih cepat dalam tes saya di Chrome (2013/03/21). Sekitar 200ms untuk 10.000.000 elemen vs 675 untuk init langsung.Bonus: jika Anda ingin mengisi array Anda dengan Strings, ini adalah cara ringkas untuk melakukannya (tidak secepat secepat
concat
):sumber
Saya sedang menguji jawaban yang bagus oleh TJ Crowder, dan muncul dengan penggabungan rekursif berdasarkan solusi concat yang mengungguli apa pun dalam tesnya di Chrome (saya tidak menguji browser lain).
panggil metode dengan
makeRec(29)
.sumber
Bagaimana dengan
new Array(51).join('0').split('')
?sumber
.map(function(a){return +a})
?Mungkin layak untuk ditunjukkan, yang
Array.prototype.fill
telah ditambahkan sebagai bagian dari proposal ECMAScript 6 (Harmony) . Saya lebih suka menggunakan polyfill yang tertulis di bawah, sebelum mempertimbangkan opsi lain yang disebutkan di utas.sumber
Kode terpendek untuk loop
Versi var aman
sumber
n
, maka ini akan menjadi lebih pendek:for(var a=[];n--;a[n]=0);
sumber
Fungsi tercepat saya adalah:
Menggunakan push dan shift asli untuk menambahkan item ke array jauh lebih cepat (sekitar 10 kali) daripada mendeklarasikan ruang lingkup array dan mereferensikan setiap item untuk menetapkan nilainya.
fyi: Saya secara konsisten mendapatkan waktu yang lebih cepat dengan loop pertama, yang menghitung mundur, ketika menjalankan ini di pembakar (ekstensi firefox).
Saya tertarik untuk mengetahui apa yang membuat TJ Crowder tentang itu? :-)
sumber
while (len--)
.. butuh waktu pemrosesan saya dari sekitar 60 ms menjadi sekitar 54 msAku tahu aku punya proto di suatu tempat ini :)
Edit: tes
Menanggapi metode Joshua dan lainnya saya menjalankan tolok ukur saya sendiri, dan saya melihat hasil yang sangat berbeda dengan yang dilaporkan.
Inilah yang saya uji:
Hasil:
Jadi dengan perhitungan saya memang lebih lambat pada umumnya tetapi berkinerja lebih baik dengan array yang lebih panjang di FF tetapi lebih buruk di IE yang hanya menyebalkan secara umum (quel surprise).
sumber
b = []...
) adalah 10-15% lebih cepat dari yang pertama, tetapi lebih dari 10 kali lebih lambat dari jawaban Joshua.else {this.length=n;}
setelahthis.length
centang. Ini akan memperpendek array yang sudah ada jika perlu ketikainit
memanggil ulang ke panjang yang berbedan
.Fungsi anonim:
Sedikit lebih pendek dengan for-loop:
Bekerja dengan apa pun
Object
, ubah saja apa yang ada di dalamnyathis.push()
.Anda bahkan dapat menyimpan fungsi:
Sebut menggunakan:
Menambahkan elemen ke array yang sudah ada:
Kinerja: http://jsperf.com/zero-filled-array-creation/25
sumber