Apa cara paling efisien untuk membuat array panjang nol yang diisi secara sewenang-wenang dalam JavaScript?
let i = 0; Array.from(Array(10), ()=>i++);
Apa cara paling efisien untuk membuat array panjang nol yang diisi secara sewenang-wenang dalam JavaScript?
let i = 0; Array.from(Array(10), ()=>i++);
Jawaban:
ES6 memperkenalkan Array.prototype.fill
. Dapat digunakan seperti ini:
new Array(len).fill(0);
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 .
new Array(len)
sangat lambat. (arr = []).length = len; arr.fill(0);
adalah tentang solusi tercepat ive terlihat di mana saja ... atau setidaknya terikat
arr = 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;
terhadap arr = new Array(1000);
kecepatan, ujilah di Chrome dan FF ... prosesnya new
sangat lambat. Sekarang, untuk panjang array yang lebih kecil .. katakan <50 atau ada sekitar ... maka new Array()
tampaknya berkinerja lebih baik. Tapi ..
arr.fill(0)
... semuanya berubah. Sekarang, menggunakan new 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'));
vs new 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:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]
Jika saya ingin mengisi sebelumnya dengan string:
Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]
Jawaban lain telah menyarankan:
new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]
tetapi jika Anda ingin 0 (angka) dan bukan "0" (nol di dalam string), Anda dapat melakukan:
new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]
Array.apply(null, new Array(5)).map(...)
? Karena cukup melakukan (new Array (5)). Map (...) tidak akan berfungsi seperti yang diceritakan oleh spec
new
) Saat Anda melakukannya, Array(5)
Anda membuat objek yang terlihat seperti ini: { length: 5, __proto__: Array.prototype }
- coba console.dir( Array(5) )
. Perhatikan bahwa itu tidak memiliki sifat setiap 0
, 1
, 2
, dll Tapi ketika Anda apply
bahwa kepada Array
konstruktor, itu seperti mengatakan Array(undefined, undefined, undefined, undefined, undefined)
. Dan Anda mendapatkan objek yang agak mirip { length: 5, 0: undefined, 1: undefined...}
. map
bekerja pada properti 0
,, 1
dll. itulah sebabnya contoh Anda tidak berfungsi, tetapi ketika Anda menggunakannya apply
tidak.
.apply
sebenarnya adalah yang Anda inginkan this
. Untuk tujuan this
ini, tidak masalah - kami hanya benar-benar peduli tentang penyebaran "fitur" parameter .apply
- sehingga dapat berupa nilai apa pun. Saya suka null
karena murah, Anda mungkin tidak ingin menggunakan {}
atau []
karena Anda akan membuat objek tanpa alasan.
Berikut ini cara lain untuk melakukannya menggunakan ES6 yang sejauh ini belum ada yang disebutkan:
> Array.from(Array(3), () => 0)
< [0, 0, 0]
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 nilai 0
.
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:
> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]
Ini lebih ringkas (dan elegan) daripada yang setara:
const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
numbers[i] = Math.round(10 * Math.random());
}
Metode ini juga dapat digunakan untuk menghasilkan urutan angka dengan memanfaatkan parameter indeks yang disediakan dalam panggilan balik:
> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
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:
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
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 kemudian map()
ped ke nilai yang kita inginkan. Hancurkan dalam beberapa langkah:
> "?".repeat(10)
< "??????????"
> "?".repeat(10).split("")
< ["?", "?", "?", "?", "?", "?", "?", "?", "?", "?"]
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
repeat
triknya jelas tidak diinginkan dalam produksi, Array.from()
baik-baik saja :-)
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)
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
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 memanggilnya push(..)
) 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 besar
Kode di bawah ini menyajikan solusi yang digunakan dalam pengukuran
Contoh hasil untuk Chrome
let a=[]; for(i=n;i--;) a.push(0);
- tetapi 4x lebih lambat dari fill(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
a = new Array(10).fill(0);
Mengingat dukungan browser saat ini, Anda harus berhati-hati untuk menggunakan ini kecuali Anda yakin audiens Anda menggunakan browser Desktop modern.
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], seperti Int32Array
dan itu. Perhatikan juga bahwa ES2015 menambahkan fill
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:
function newFilledArray(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = val;
}
return rv;
}
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 ):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Zero Init Test Page</title>
<style type='text/css'>
body {
font-family: sans-serif;
}
#log p {
margin: 0;
padding: 0;
}
.error {
color: red;
}
.winner {
color: green;
font-weight: bold;
}
</style>
<script type='text/javascript' src='prototype-1.6.0.3.js'></script>
<script type='text/javascript'>
var testdefs = {
'downpre': {
total: 0,
desc: "Count down, pre-decrement",
func: makeWithCountDownPre
},
'downpost': {
total: 0,
desc: "Count down, post-decrement",
func: makeWithCountDownPost
},
'up': {
total: 0,
desc: "Count up (normal)",
func: makeWithCountUp
},
'downandup': {
total: 0,
desc: "Count down (for loop) and up (for filling)",
func: makeWithCountDownArrayUp
},
'concat': {
total: 0,
desc: "Concat",
func: makeWithConcat
}
};
document.observe('dom:loaded', function() {
var markup, defname;
markup = "";
for (defname in testdefs) {
markup +=
"<div><input type='checkbox' id='chk_" + defname + "' checked>" +
"<label for='chk_" + defname + "'>" + testdefs[defname].desc + "</label></div>";
}
$('checkboxes').update(markup);
$('btnTest').observe('click', btnTestClick);
});
function epoch() {
return (new Date()).getTime();
}
function btnTestClick() {
// Clear log
$('log').update('Testing...');
// Show running
$('btnTest').disabled = true;
// Run after a pause while the browser updates display
btnTestClickPart2.defer();
}
function btnTestClickPart2() {
try {
runTests();
}
catch (e) {
log("Exception: " + e);
}
// Re-enable the button; we don't yheidl
$('btnTest').disabled = false;
}
function runTests() {
var start, time, counter, length, defname, def, results, a, invalid, lowest, s;
// Get loops and length
s = $F('txtLoops');
runcount = parseInt(s);
if (isNaN(runcount) || runcount <= 0) {
log("Invalid loops value '" + s + "'");
return;
}
s = $F('txtLength');
length = parseInt(s);
if (isNaN(length) || length <= 0) {
log("Invalid length value '" + s + "'");
return;
}
// Clear log
$('log').update('');
// Do it
for (counter = 0; counter <= runcount; ++counter) {
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
start = epoch();
a = def.func(length);
time = epoch() - start;
if (counter == 0) {
// Don't count (warm up), but do check the algorithm works
invalid = validateResult(a, length);
if (invalid) {
log("<span class='error'>FAILURE</span> with def " + defname + ": " + invalid);
return;
}
}
else {
// Count this one
log("#" + counter + ": " + def.desc + ": " + time + "ms");
def.total += time;
}
}
}
}
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
def.avg = def.total / runcount;
if (typeof lowest != 'number' || lowest > def.avg) {
lowest = def.avg;
}
}
}
results =
"<p>Results:" +
"<br>Length: " + length +
"<br>Loops: " + runcount +
"</p>";
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
results += "<p" + (lowest == def.avg ? " class='winner'" : "") + ">" + def.desc + ", average time: " + def.avg + "ms</p>";
}
}
results += "<hr>";
$('log').insert({top: results});
}
function validateResult(a, length) {
var n;
if (a.length != length) {
return "Length is wrong";
}
for (n = length - 1; n >= 0; --n) {
if (a[n] != 0) {
return "Index " + n + " is not zero";
}
}
return undefined;
}
function makeWithCountDownPre(len) {
var a;
a = new Array(len);
while (--len >= 0) {
a[len] = 0;
}
return a;
}
function makeWithCountDownPost(len) {
var a;
a = new Array(len);
while (len-- > 0) {
a[len] = 0;
}
return a;
}
function makeWithCountUp(len) {
var a, i;
a = new Array(len);
for (i = 0; i < len; ++i) {
a[i] = 0;
}
return a;
}
function makeWithCountDownArrayUp(len) {
var a, i;
a = new Array(len);
i = 0;
while (--len >= 0) {
a[i++] = 0;
}
return a;
}
function makeWithConcat(len) {
var a, rem, currlen;
if (len == 0) {
return [];
}
a = [0];
currlen = 1;
while (currlen < len) {
rem = len - currlen;
if (rem < currlen) {
a = a.concat(a.slice(0, rem));
}
else {
a = a.concat(a);
}
currlen = a.length;
}
return a;
}
function log(msg) {
$('log').appendChild(new Element('p').update(msg));
}
</script>
</head>
<body><div>
<label for='txtLength'>Length:</label><input type='text' id='txtLength' value='10000'>
<br><label for='txtLoops'>Loops:</label><input type='text' id='txtLoops' value='10'>
<div id='checkboxes'></div>
<br><input type='button' id='btnTest' value='Test'>
<hr>
<div id='log'></div>
</div></body>
</html>
Secara default Uint8Array
, Uint16Array
dan Uint32Array
kelas menyimpan nol sebagai nilainya, jadi Anda tidak perlu teknik pengisian yang rumit, cukup lakukan:
var ary = new Uint8Array(10);
semua elemen array ary
akan menjadi nol secara default.
Array.isArray(ary)
adalah false
. 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 sebesar 0
. 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:
Array.from({ length: 3 }, () => 0);
//[0, 0, 0]
Memiliki hasil yang sama dengan
Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]
Karena
Array.from({ length: 3 })
//[undefined, undefined, undefined]
function makeArrayOf(value, length) {
var arr = [], i = length;
while (i--) {
arr[i] = value;
}
return arr;
}
makeArrayOf(0, 5); // [0, 0, 0, 0, 0]
makeArrayOf('x', 3); // ['x', 'x', 'x']
Perhatikan bahwa while
biasanya lebih efisien daripada for-in
, forEach
, dll
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 menggunakannya arr.push(value)
. Ini menjengkelkan, karena saya lebih suka metode Anda.
menggunakan notasi objek
var x = [];
nol diisi? Suka...
var x = [0,0,0,0,0,0];
diisi dengan 'tidak terdefinisi' ...
var x = new Array(7);
notasi obj dengan nol
var x = [];
for (var i = 0; i < 10; i++) x[i] = 0;
Sebagai catatan, jika Anda memodifikasi prototipe Array, keduanya
var x = new Array();
dan
var y = [];
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.
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.
function newFilledArray(length, val) {
var array = [];
for (var i = 0; i < length; i++) {
array[i] = val;
}
return array;
}
atau
function newFilledArray(length, val) {
var array = [];
var i = 0;
while (i < length) {
array[i++] = val;
}
return array;
}
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 mengatur array.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 sebuah for
loop ... tetapi init tidak lagi diperlukan, sehingga while
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:
var zero = newFilledArray(maxLength, 0);
Sekarang iris array ini setiap kali Anda membutuhkan array panjang yang diisi nol, dibutuhkan Panjang < maxLength :
zero.slice(0, requiredLength);
Saya membuat nol array yang diisi ribuan kali selama eksekusi kode saya, ini mempercepat proses dengan luar biasa.
Saya tidak menentang:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);
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 kompatibilitas
new Array(3).fill(0)
akan memberimu [0, 0, 0]
. Anda dapat mengisi array dengan nilai apa saja seperti new Array(5).fill('abc')
(bahkan objek dan array lainnya).
Selain itu, Anda dapat memodifikasi array sebelumnya dengan mengisi:
arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5) # what to fill, start, end
yang memberi Anda: [1, 2, 3, 9, 9, 6]
Cara saya biasanya melakukannya (dan sangat cepat) menggunakan Uint8Array
. Misalnya, membuat vektor elemen 1M yang diisi nol:
var zeroFilled = [].slice.apply(new Uint8Array(1000000))
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:
var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000))
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.
Menggunakan lodash atau garis bawah
_.range(0, length - 1, 0);
Atau jika Anda memiliki array yang ada dan Anda ingin array dengan panjang yang sama
array.map(_.constant(0));
_.range(0, length, 0)
, saya percaya. Lodash tidak termasuk nilai akhir
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.
const arr = [];
arr.length = 120000;
let i = 0;
while (i < 120000) {
arr[i] = 0;
i++;
}
Kemungkinan implementasi lain adalah:
(arr = []).length = n;
let i = 0;
while (i < n) {
arr[i] = 0;
i++;
}
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
const arr = Array(n).fill(0);
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. Gunakan const
untuk variabel yang tidak akan didefinisikan ulang dan let
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.
Untuk membuat Array baru
new Array(arrayLength).fill(0);
Untuk menambahkan beberapa nilai di akhir Array yang ada
[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]
//**To create an all new Array**
console.log(new Array(5).fill(0));
//**To add some values at the end of an existing Array**
let existingArray = [1,2,3]
console.log([...existingArray, ...new Array(5).fill(0)]);
Tidak melihat metode ini dalam jawaban, jadi ini dia:
"0".repeat( 200 ).split("").map( parseFloat )
Hasilnya, Anda akan mendapatkan array bernilai nol dengan panjang 200:
[ 0, 0, 0, 0, ... 0 ]
Saya tidak yakin tentang kinerja kode ini, tetapi seharusnya tidak menjadi masalah jika Anda menggunakannya untuk array yang relatif kecil.
const arr = Array.from({ length: 10 }).fill(0)
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.
function filledArray(len, value) {
if (len <= 0) return [];
var result = [value];
while (result.length < len/2) {
result = result.concat(result);
}
return result.concat(result.slice(0, len-result.length));
}
Bonus: jika Anda ingin mengisi array Anda dengan Strings, ini adalah cara ringkas untuk melakukannya (tidak secepat secepat concat
):
function filledArrayString(len, value) {
return new Array(len+1).join(value).split('');
}
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).
function makeRec(len, acc) {
if (acc == null) acc = [];
if (len <= 1) return acc;
var b = makeRec(len >> 1, [0]);
b = b.concat(b);
if (len & 1) b = b.concat([0]);
return b;
},
panggil metode dengan makeRec(29)
.
Bagaimana dengan new Array(51).join('0').split('')
?
.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.
if (!Array.prototype.fill) {
Array.prototype.fill = function(value) {
// Steps 1-2.
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
// Steps 3-5.
var len = O.length >>> 0;
// Steps 6-7.
var start = arguments[1];
var relativeStart = start >> 0;
// Step 8.
var k = relativeStart < 0 ?
Math.max(len + relativeStart, 0) :
Math.min(relativeStart, len);
// Steps 9-10.
var end = arguments[2];
var relativeEnd = end === undefined ?
len : end >> 0;
// Step 11.
var final = relativeEnd < 0 ?
Math.max(len + relativeEnd, 0) :
Math.min(relativeEnd, len);
// Step 12.
while (k < final) {
O[k] = value;
k++;
}
// Step 13.
return O;
};
}
Kode terpendek untuk loop
a=i=[];for(;i<100;)a[i++]=0;
edit:
for(a=i=[];i<100;)a[i++]=0;
or
for(a=[],i=100;i--;)a[i]=0;
Versi var aman
var a=[],i=0;for(;i<100;)a[i++]=0;
edit:
for(var i=100,a=[];i--;)a[i]=0;
n
, maka ini akan menjadi lebih pendek:for(var a=[];n--;a[n]=0);
let filled = [];
filled.length = 10;
filled.fill(0);
console.log(filled);
Fungsi tercepat saya adalah:
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
var st = (new Date()).getTime();
newFilledArray(1000000, 0)
console.log((new Date()).getTime() - st); // returned 63, 65, 62 milliseconds
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).
var a = [];
var len = 1000000;
var st = (new Date()).getTime();
while(len){
a.push(0);
len -= 1;
}
console.log((new Date()).getTime() - st); // returned 863, 894, 875 milliseconds
st = (new Date()).getTime();
len = 1000000;
a = [];
for(var i = 0; i < len; i++){
a.push(0);
}
console.log((new Date()).getTime() - st); // returned 1155, 1179, 1163 milliseconds
Saya tertarik untuk mengetahui apa yang membuat TJ Crowder tentang itu? :-)
while (len--)
.. butuh waktu pemrosesan saya dari sekitar 60 ms menjadi sekitar 54 ms
Aku tahu aku punya proto di suatu tempat ini :)
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
var a = (new Array(5)).init(0);
var b = [].init(0,4);
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:
//my original method
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
//now using push which I had previously thought to be slower than direct assignment
Array.prototype.init2 = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this.push(x); }
return this;
}
//joshua's method
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
//test m1 and m2 with short arrays many times 10K * 10
var a = new Date();
for(var i=0; i<10000; i++)
{
var t1 = [].init(0,10);
}
var A = new Date();
var b = new Date();
for(var i=0; i<10000; i++)
{
var t2 = [].init2(0,10);
}
var B = new Date();
//test m1 and m2 with long array created once 100K
var c = new Date();
var t3 = [].init(0,100000);
var C = new Date();
var d = new Date();
var t4 = [].init2(0,100000);
var D = new Date();
//test m3 with short array many times 10K * 10
var e = new Date();
for(var i=0; i<10000; i++)
{
var t5 = newFilledArray(10,0);
}
var E = new Date();
//test m3 with long array created once 100K
var f = new Date();
var t6 = newFilledArray(100000, 0)
var F = new Date();
Hasil:
IE7 deltas:
dA=156
dB=359
dC=125
dD=375
dE=468
dF=412
FF3.5 deltas:
dA=6
dB=13
dC=63
dD=8
dE=12
dF=8
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).
b = []...
) adalah 10-15% lebih cepat dari yang pertama, tetapi lebih dari 10 kali lebih lambat dari jawaban Joshua.
else {this.length=n;}
setelah this.length
centang. Ini akan memperpendek array yang sudah ada jika perlu ketika init
memanggil ulang ke panjang yang berbeda n
.
Fungsi anonim:
(function(n) { while(n-- && this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Sedikit lebih pendek dengan for-loop:
(function(n) { for(;n--;this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Bekerja dengan apa pun Object
, ubah saja apa yang ada di dalamnya this.push()
.
Anda bahkan dapat menyimpan fungsi:
function fill(size, content) {
for(;size--;this.push(content));
return this;
}
Sebut menggunakan:
var helloArray = fill.call([], 5, 'hello');
// => ['hello', 'hello', 'hello', 'hello', 'hello']
Menambahkan elemen ke array yang sudah ada:
var helloWorldArray = fill.call(helloArray, 5, 'world');
// => ['hello', 'hello', 'hello', 'hello', 'hello', 'world', 'world', 'world', 'world', 'world']