วิธีที่มีประสิทธิภาพที่สุดในการสร้างอาร์เรย์ที่เติมเต็มความยาวเป็นศูนย์ใน JavaScript คืออะไร?
let i = 0; Array.from(Array(10), ()=>i++);
วิธีที่มีประสิทธิภาพที่สุดในการสร้างอาร์เรย์ที่เติมเต็มความยาวเป็นศูนย์ใน JavaScript คืออะไร?
let i = 0; Array.from(Array(10), ()=>i++);
คำตอบ:
Array.prototype.fill
แนะนำ ES6 มันสามารถใช้เช่นนี้:
new Array(len).fill(0);
ไม่แน่ใจว่ามันเร็ว แต่ฉันชอบเพราะสั้นและอธิบายตัวเองได้
ก็ยังคงไม่ได้อยู่ใน IE ( เข้ากันได้ตรวจสอบ ) แต่มีpolyfill ใช้ได้
new Array(len)
ช้าลงอย่างเจ็บปวด (arr = []).length = len; arr.fill(0);
เป็นเรื่องเกี่ยวกับวิธีแก้ปัญหาที่เร็วที่สุด ive เห็นได้ทุกที่ ... หรืออย่างน้อยก็ผูก
arr = Array(n)
และ(arr = []).length = n
ทำงานเหมือนกันตามข้อมูลจำเพาะ ในการใช้งานบางอย่างอาจเร็วขึ้น แต่ฉันไม่คิดว่าจะมีความแตกต่างใหญ่
(arr = []).length = 1000;
เทียบกับarr = new Array(1000);
ความเร็วทดสอบทั้งใน Chrome และ FF ... new
มันช้ามาก ทีนี้สำหรับความยาวของอาเรย์ที่น้อยกว่า .. พูด <50 หรือประมาณนั้น ... new Array()
ดูเหมือนว่าจะทำงานได้ดีขึ้น แต่ ..
arr.fill(0)
... การเปลี่ยนแปลงทุกอย่างเรียงลำดับ ตอนนี้การใช้งานnew Array()
จะเร็วขึ้นในกรณีส่วนใหญ่ยกเว้นเมื่อคุณไปถึงขนาดอาร์เรย์> 100000 ... จากนั้นคุณสามารถเริ่มเห็นการเพิ่มความเร็วอีกครั้ง แต่ถ้าคุณไม่จำเป็นต้องเติมมันด้วยศูนย์และสามารถใช้อาร์เรย์ที่มีความไม่แน่นอนของอาร์เรย์ว่างได้ จากนั้น(arr = []).length = x
จะบ้าเร็วในกรณีทดสอบของฉันเกือบตลอดเวลา
new Array(5).forEach(val => console.log('hi'));
new Array(5).fill(undefined).forEach(val => console.log('hi'));
แม้ว่านี่จะเป็นเธรดเก่า แต่ฉันต้องการเพิ่ม 2 เซนต์ของฉันลงไป ไม่แน่ใจว่านี่ช้า / เร็วแค่ไหน แต่มันก็เป็นซับรวดเร็ว นี่คือสิ่งที่ฉันทำ:
หากฉันต้องการกรอกหมายเลขล่วงหน้า:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]
หากฉันต้องการเติมสตริงล่วงหน้า:
Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]
คำตอบอื่น ๆ ได้แนะนำ:
new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]
แต่ถ้าคุณต้องการ 0 (ตัวเลข) และไม่ใช่ "0" (ศูนย์ภายในสตริง) คุณสามารถทำได้:
new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]
Array.apply(null, new Array(5)).map(...)
มั้ย สาเหตุเพียงทำ (อาร์เรย์ใหม่ (5)). แผนที่ (... ) จะไม่ทำงานตามที่สเป็คบอก
new
) เมื่อคุณทำArray(5)
คุณกำลังสร้างวัตถุที่ดูเหมือนเป็นนี้: { length: 5, __proto__: Array.prototype }
- console.dir( Array(5) )
ลอง ขอให้สังเกตว่ามันไม่ได้มีคุณสมบัติใด ๆ0
, 1
, 2
ฯลฯ แต่เมื่อคุณapply
ว่าแก่คอนสตรัคก็ชอบพูดว่าArray
และคุณจะได้รับวัตถุนั้นครับดูเหมือนว่าArray(undefined, undefined, undefined, undefined, undefined)
ทำงานบนคุณสมบัติ, ฯลฯ ซึ่งเป็นเหตุผลที่ตัวอย่างของคุณไม่ได้ทำงาน แต่เมื่อคุณใช้มันไม่ { length: 5, 0: undefined, 1: undefined...}
map
0
1
apply
.apply
คือสิ่งที่คุณต้องการthis
ให้เป็น สำหรับวัตถุประสงค์เหล่านี้this
ไม่สำคัญ - เราใส่ใจเฉพาะเกี่ยวกับการแพร่กระจายพารามิเตอร์ "คุณสมบัติ" ของ.apply
- ดังนั้นจึงสามารถเป็นค่าใด ๆ ฉันชอบnull
เพราะมันราคาถูกคุณอาจไม่ต้องการใช้{}
หรือ[]
เพราะคุณกำลังยกวัตถุให้โดยไม่มีเหตุผล
นี่เป็นอีกวิธีในการใช้ ES6 ที่ไม่มีใครพูดถึง:
> Array.from(Array(3), () => 0)
< [0, 0, 0]
มันทำงานได้โดยผ่านฟังก์ชั่นแผนที่เป็นพารามิเตอร์ที่สองของ Array.from
มันทำงานโดยผ่านฟังก์ชั่นแผนที่เป็นพารามิเตอร์ที่สองของ
ในตัวอย่างข้างต้นพารามิเตอร์แรกจัดสรรอาร์เรย์ 3 ตำแหน่งที่เติมด้วยค่าundefined
จากนั้นฟังก์ชัน lambda จะจับคู่แต่ละค่ากับค่า0
แล้วฟังก์ชั่นแลมบ์ดาแผนที่หนึ่งของพวกเขาแต่ละค่า
แม้ว่าArray(len).fill(0)
จะสั้นกว่า แต่ก็ไม่ได้ผลถ้าคุณต้องการเติมอาร์เรย์ด้วยการคำนวณบางอย่างก่อน(ฉันรู้ว่าคำถามไม่ได้ถาม แต่มีคนมากมายที่มาหาที่นี่)แต่คนจำนวนมากจะจบลงที่นี่มองหานี้)
ตัวอย่างเช่นหากคุณต้องการอาร์เรย์ที่มีตัวเลขสุ่ม 10 ตัว:
> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]
มันกระชับมากขึ้น (และสง่างาม) มากกว่าสิ่งที่เทียบเท่า:
const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
numbers[i] = Math.round(10 * Math.random());
}
วิธีนี้ยังสามารถใช้เพื่อสร้างลำดับของตัวเลขโดยใช้ประโยชน์จากพารามิเตอร์ดัชนีที่มีให้ในการเรียกกลับ:
> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
repeat()
เนื่องจากคำตอบนี้ได้รับความสนใจเป็นอย่างมากฉันจึงต้องการแสดงกลเม็ดเด็ดพรายนี้ แม้ว่าจะไม่ได้มีประโยชน์เท่าคำตอบหลักของฉัน แต่จะแนะนำrepeat()
วิธีการสตริงที่ยังไม่ค่อยมีใครรู้จัก แต่มีประโยชน์มาก นี่คือเคล็ดลับ:
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
เจ๋งใช่มั้ย repeat()
เป็นวิธีที่มีประโยชน์มากในการสร้างสตริงที่มีการทำซ้ำของสายอักขระในจำนวนครั้งที่แน่นอน หลังจากนั้นsplit()
สร้างอาร์เรย์ให้เราซึ่งจากนั้นmap()
ไปที่ค่าที่เราต้องการ ทำลายมันลงในขั้นตอน:
> "?".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
เคล็ดลับจะไม่ต้องการในการผลิตแน่นอนArray.from()
ดี :-) อย่างสมบูรณ์แบบ
ทางออกที่เร็วที่สุด
let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;
ทางออกที่สั้นที่สุด (มีประโยชน์) (ช้าลง 3 เท่าสำหรับอาร์เรย์ขนาดเล็ก, ช้าลงเล็กน้อยสำหรับใหญ่ (ช้าที่สุดบน Firefox))
Array(n).fill(0)
วันนี้ 2020.06.09 ฉันทำการทดสอบบน macOS High Sierra 10.13.6 บนเบราว์เซอร์ Chrome 83.0, Firefox 77.0 และ Safari 13.1 ฉันทดสอบโซลูชันที่เลือกสำหรับกรณีทดสอบสองกรณี
new Array(n)+for
(N) เป็นวิธีแก้ปัญหาที่เร็วที่สุดสำหรับอาร์เรย์ขนาดเล็กและอาร์เรย์ขนาดใหญ่ (ยกเว้น Chrome แต่ยังเร็วมาก) และแนะนำให้ใช้เป็นโซลูชันข้ามเบราว์เซอร์ที่รวดเร็วnew Float32Array(n)
(I) ส่งกลับไม่ใช่อาร์เรย์ทั่วไป (เช่นคุณไม่สามารถโทรpush(..)
ได้) ดังนั้นฉันจึงไม่เปรียบเทียบผลลัพธ์กับโซลูชันอื่น ๆ - อย่างไรก็ตามโซลูชันนี้เร็วกว่าประมาณ 10-20 เท่าเมื่อเทียบกับโซลูชันอื่น ๆ สำหรับเบราว์เซอร์ขนาดใหญ่for
(L, M, N, O) นั้นรวดเร็วสำหรับอาร์เรย์ขนาดเล็กfill
(B, C) นั้นรวดเร็วบน Chrome และ Safari แต่ช้าที่สุดใน Firefox สำหรับอาร์เรย์ขนาดใหญ่ มีขนาดกลางเร็วสำหรับอาร์เรย์ขนาดเล็กArray.apply
(P) พ่นข้อผิดพลาดสำหรับอาร์เรย์ขนาดใหญ่
โค้ดด้านล่างแสดงโซลูชันที่ใช้ในการวัด
ตัวอย่างผลลัพธ์สำหรับ Chrome
let a=[]; for(i=n;i--;) a.push(0);
- แต่ช้ากว่า 4x fill(0)
- ดังนั้นฉันจะไม่อัปเดตรูปภาพแม่มดในกรณีนั้น
วิธีการเติม ES 6 ที่กล่าวถึงแล้วจะดูแลเรื่องนี้เป็นอย่างดี เบราว์เซอร์เดสก์ท็อปที่ทันสมัยส่วนใหญ่สนับสนุนวิธีแบบ Array ต้นที่ต้องการแล้วในปัจจุบัน (Chromium, FF, Edge และ Safari) [ 1 ] คุณสามารถดูรายละเอียดเกี่ยวกับMDN ตัวอย่างการใช้งานที่เรียบง่ายคือ
a = new Array(10).fill(0);
เมื่อได้รับการสนับสนุนเบราว์เซอร์ปัจจุบันคุณควรใช้ความระมัดระวังหากคุณไม่แน่ใจว่าผู้ชมของคุณใช้เบราว์เซอร์เดสก์ท็อปที่ทันสมัย
a = Array(10).fill(null).map(() => { return []; });
a = Array(10).fill(0).map( _ => [] );
หมายเหตุเพิ่มสิงหาคม 2013, ปรับปรุงกุมภาพันธ์ 2015: คำตอบด้านล่างจาก 2009 เกี่ยวข้องกับArray
ประเภททั่วไปของ JavaScript ไม่เกี่ยวข้องกับอาร์เรย์ที่พิมพ์ใหม่กว่าที่กำหนดใน ES2015 [และมีให้ใช้งานในเบราว์เซอร์จำนวนมาก] Int32Array
เช่นนี้ นอกจากนี้โปรดทราบว่า ES2015 เพิ่มfill
วิธีการทั้งอาร์เรย์และอาร์เรย์ที่พิมพ์ซึ่งน่าจะเป็นวิธีที่มีประสิทธิภาพที่สุดในการกรอกข้อมูล ...
นอกจากนี้ยังสามารถสร้างความแตกต่างใหญ่สำหรับการใช้งานบางอย่างว่าคุณสร้างอาร์เรย์ โดยเฉพาะอย่างยิ่งเอ็นจิ้น V8 ของ Chrome พยายามที่จะใช้อาเรย์หน่วยความจำที่ต่อเนื่องและมีประสิทธิภาพสูงหากคิดว่ามันสามารถเปลี่ยนเป็นอาเรย์แบบออบเจ็กต์เมื่อจำเป็นเท่านั้น
ด้วยภาษาส่วนใหญ่จะได้รับการจัดสรรล่วงหน้าจากนั้นเติมศูนย์แบบนี้:
function newFilledArray(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = val;
}
return rv;
}
แต่อาร์เรย์ของ JavaScript ไม่ได้เป็นอาร์เรย์จริงๆมันเป็นคีย์แผนที่ / ค่าเช่นเดียวกับวัตถุ JavaScript อื่น ๆ ดังนั้นจึงไม่มี "การจัดสรรล่วงหน้า" ที่ต้องทำ (การตั้งค่าความยาวไม่ได้เป็นการจัดสรรช่องที่จะเติม) และ มีเหตุผลใดที่เชื่อได้ว่าประโยชน์ของการนับเป็นศูนย์ (ซึ่งเป็นเพียงเพื่อทำการเปรียบเทียบในลูปอย่างรวดเร็ว) ไม่เกินดุลโดยการเพิ่มคีย์ในลำดับย้อนกลับเมื่อการนำไปปฏิบัติอาจเพิ่มประสิทธิภาพการจัดการคีย์ เกี่ยวข้องกับอาร์เรย์ในทฤษฎีที่คุณมักทำตามลำดับ
ในความเป็นจริง Matthew Crumley ชี้ให้เห็นว่าการนับถอยหลังช้าลงอย่างเห็นได้ชัดบน Firefox มากกว่าการนับผลลัพธ์ที่ฉันยืนยันได้ - เป็นส่วนของอาร์เรย์ (การวนซ้ำลงไปที่ศูนย์ยังคงเร็วกว่า เห็นได้ชัดว่าการเพิ่มองค์ประกอบให้กับอาร์เรย์ในลำดับย้อนกลับเป็น op ที่ช้าใน Firefox อันที่จริงผลลัพธ์นั้นแตกต่างกันเล็กน้อยโดยการใช้งาน JavaScript (ซึ่งไม่ใช่สิ่งที่น่าแปลกใจ) ต่อไปนี้เป็นหน้าทดสอบที่รวดเร็วและสกปรก (ด้านล่าง) สำหรับการใช้งานเบราว์เซอร์ (สกปรกมากไม่ให้ผลในระหว่างการทดสอบดังนั้นให้ข้อเสนอแนะน้อยที่สุดและจะทำงานโดยไม่ จำกัด เวลาสคริปต์) ฉันขอแนะนำให้รีเฟรชระหว่างการทดสอบ FF (อย่างน้อย) ช้าลงในการทดสอบซ้ำหากคุณไม่ทำ
เวอร์ชันที่ค่อนข้างซับซ้อนที่ใช้ Array # concat นั้นเร็วกว่า init โดยตรงบน FF เนื่องจากอยู่ระหว่าง 1,000 ถึง 2,000 อาร์เรย์ อย่างไรก็ตามในเครื่องมือ V8 ของ Chrome การชนะโดยตรงจะชนะทุกครั้ง ...
นี่คือหน้าทดสอบ ( สำเนาสด ):
<!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>
โดยค่าเริ่มต้นUint8Array
, Uint16Array
และUint32Array
ชั้นเรียนให้ศูนย์เป็นค่าของตนเพื่อให้คุณไม่จำเป็นต้องกรอกข้อมูลใด ๆ เทคนิคที่ซับซ้อนเพียงแค่ทำ:
var ary = new Uint8Array(10);
องค์ประกอบทั้งหมดของอาร์เรย์ary
จะเป็นศูนย์โดยค่าเริ่มต้น
Array.isArray(ary)
false
ความยาวเป็นแบบอ่านอย่างเดียวดังนั้นคุณจึงไม่สามารถผลักรายการใหม่ ๆ ไปได้เช่นเดียวกับary.push
0
เป็นค่าเริ่มต้น
Array.from(new Uint8Array(10))
จะให้อาร์เรย์ปกติ
Array(n).fill(0)
ใน Chrome ประมาณ 5 เท่าถ้าสิ่งที่คุณต้องการจริงๆคือ JS Array หากคุณสามารถใช้ TypedArray นี้เป็นได้เร็วขึ้นมากแม้กว่าแต่โดยเฉพาะอย่างยิ่งถ้าคุณสามารถใช้ค่าเริ่มต้นการเริ่มต้นค่าของ.fill(0)
0
ดูเหมือนจะไม่มีคอนสตรัคเตอร์ที่ใช้ค่าเติมและความยาวตามที่ C ++ std::vector
มี ดูเหมือนว่าค่าที่ไม่เป็นศูนย์ใด ๆ ที่คุณต้องสร้าง TypedArray ที่มีค่าศูนย์แล้วเติมให้เต็ม : /
ถ้าคุณใช้ ES6 คุณสามารถใช้Array.from ()ดังนี้:
Array.from({ length: 3 }, () => 0);
//[0, 0, 0]
มีผลเช่นเดียวกัน
Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]
เพราะ
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']
โปรดทราบว่าwhile
จะมีประสิทธิภาพมากกว่ามักจะfor-in
, forEach
ฯลฯ
i
ภายนอกตัวแปรท้องถิ่น? length
ถูกส่งผ่านโดยค่าดังนั้นคุณควรจะสามารถลดได้โดยตรง
arr[i] = value
) arr.push(value)
มันมากเร็วกว่าที่จะห่วงผ่านตั้งแต่ต้นจนจบและการใช้งาน มันน่ารำคาญเพราะฉันชอบวิธีการของคุณ
ใช้สัญกรณ์วัตถุ
var x = [];
เต็มไปด้วยศูนย์? ชอบ...
var x = [0,0,0,0,0,0];
เต็มไปด้วย 'ไม่ได้กำหนด' ...
var x = new Array(7);
สัญกรณ์ obj กับศูนย์
var x = [];
for (var i = 0; i < 10; i++) x[i] = 0;
ในฐานะที่เป็นบันทึกด้านข้างหากคุณปรับเปลี่ยนต้นแบบของ Array ทั้งคู่
var x = new Array();
และ
var y = [];
จะมีการดัดแปลงต้นแบบเหล่านั้น
ฉันจะไม่กังวลกับประสิทธิภาพหรือความเร็วของการดำเนินการมากเกินไปมีหลายสิ่งหลายอย่างที่คุณน่าจะทำซึ่งมีความสิ้นเปลืองและมีราคาแพงกว่าการติดตั้งความยาวโดยพลการที่มีเลขศูนย์
null
ในอาร์เรย์นี้ -var x = new Array(7);
new Array(7)
ไม่ได้สร้างอาร์เรย์ "เต็มไปด้วยไม่ได้กำหนด" มันสร้างอาร์เรย์ว่างเปล่าที่มีความยาว 7
(new Array(10)).fill(0)
วันนี้คุณสามารถทำ
ฉันได้ทดสอบการรวมกันของการจัดสรรล่วงหน้า / ไม่จัดสรรล่วงหน้านับรวมขึ้น / ลงและ / ในขณะที่ลูปใน IE 6/7/8, Firefox 3.5, Chrome และ Opera
ฟังก์ชั่นด้านล่างนั้นเร็วที่สุดหรือใกล้เคียงที่สุดใน Firefox, Chrome และ IE8 อย่างช้าๆและไม่ช้าไปกว่า Opera และ IE 6 ที่เร็วที่สุดเท่าไหร่มันยังง่ายและชัดเจนที่สุดในความคิดของฉัน ฉันพบเบราว์เซอร์หลายตัวที่ขณะที่รุ่นลูปนั้นเร็วขึ้นเล็กน้อยดังนั้นฉันจึงรวมเอาไว้อ้างอิงด้วย
function newFilledArray(length, val) {
var array = [];
for (var i = 0; i < length; i++) {
array[i] = val;
}
return array;
}
หรือ
function newFilledArray(length, val) {
var array = [];
var i = 0;
while (i < length) {
array[i++] = val;
}
return array;
}
var array = []
คำแถลงลงในส่วนแรกของ for loop ได้โดยคั่นด้วยเครื่องหมายจุลภาคเท่านั้น
length
ค่าที่กำหนดไว้เพื่อไม่ให้เปลี่ยนแปลงตลอดเวลา นำอาร์เรย์ความยาว 1 ล้านศูนย์จาก 40ms เป็น 8 ในเครื่องของฉัน
for (i = 0, array = []; i < length; ++i) array[i] = val;
.. บล็อกน้อยลงหรือไม่ ... อย่างไรก็ตามถ้าฉันตั้งค่าarray.length
อาร์เรย์ใหม่ตามความยาว .. ฉันดูเหมือนจะเพิ่มความเร็ว FF เพิ่มขึ้น 10% -15% ใน Chrome ... ดูเหมือนว่าจะเพิ่มความเร็วเป็นสองเท่า -> var i, array = []; array.length = length; while(i < length) array[i++] = val;
(ยังเร็วกว่านี้ถ้าฉันปล่อยให้มันเป็นfor
วง ... แต่ไม่จำเป็นต้องใช้ init อีกต่อไปดังนั้นจึงwhile
ดูเหมือนว่าจะเร็วกว่าในรุ่นนี้)
หากคุณต้องการสร้างอาร์เรย์ที่เติมศูนย์จำนวนมากที่มีความยาวต่างกันระหว่างการประมวลผลโค้ดของคุณวิธีที่เร็วที่สุดที่ฉันพบเพื่อบรรลุเป้าหมายนี้คือการสร้างอาร์เรย์ศูนย์หนึ่งครั้งโดยใช้วิธีใดวิธีหนึ่งที่กล่าวถึงในหัวข้อนี้ ที่คุณรู้ว่าจะไม่มีวันเกินจากนั้นหั่นส่วนนั้นตามความจำเป็น
ตัวอย่างเช่น (ใช้ฟังก์ชั่นจากคำตอบที่เลือกไว้ด้านบนเพื่อเริ่มต้นอาร์เรย์) สร้างอาร์เรย์ที่เต็มไปด้วยความยาวmaxLength แบบศูนย์ซึ่งเป็นตัวแปรที่มองเห็นได้จากโค้ดที่ต้องใช้ศูนย์อาร์เรย์:
var zero = newFilledArray(maxLength, 0);
ตอนนี้ฝานอาร์เรย์นี้ทุกครั้งที่คุณต้องการอาเรย์ที่เต็มไปด้วยความยาวที่ต้องการความยาวความยาว< maxLength :
zero.slice(0, requiredLength);
ฉันกำลังสร้างอาร์เรย์ที่กรอกข้อมูลเป็นศูนย์เป็นพัน ๆ ครั้งในระหว่างการประมวลผลโค้ดของฉันซึ่งทำให้กระบวนการเร็วขึ้นอย่างมาก
ฉันไม่มีอะไรกับ:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);
แนะนำโดย Zertosh แต่ในส่วนขยายของอาร์เรย์ES6 ใหม่ช่วยให้คุณสามารถทำสิ่งนี้ได้ด้วยfill
วิธีการ ตอนนี้ขอบ IE, Chrome และ FF รองรับ แต่ตรวจสอบตารางความเข้ากันได้
new Array(3).fill(0)
[0, 0, 0]
จะทำให้คุณ คุณสามารถเติมอาร์เรย์ด้วยค่าใด ๆ เช่นnew Array(5).fill('abc')
(แม้วัตถุและอาร์เรย์อื่น ๆ )
ด้านบนของที่คุณสามารถแก้ไขอาร์เรย์ก่อนหน้าด้วยการเติม:
arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5) # what to fill, start, end
ซึ่งให้คุณ: [1, 2, 3, 9, 9, 6]
วิธีที่ฉันมักจะทำมัน (และเป็นไปอย่างรวดเร็วที่น่าตื่นตาตื่นใจ) Uint8Array
คือการใช้ ตัวอย่างเช่นการสร้างเวกเตอร์ที่เติมศูนย์ขององค์ประกอบ 1M:
var zeroFilled = [].slice.apply(new Uint8Array(1000000))
ฉันเป็นผู้ใช้ Linux และมักจะทำงานให้ฉันได้ แต่เมื่อเพื่อนที่ใช้ Mac มีองค์ประกอบที่ไม่ใช่ศูนย์ ฉันคิดว่าเครื่องของเขาทำงานผิดปกติ แต่ก็ยังเป็นวิธีที่ปลอดภัยที่สุดที่เราพบในการแก้ไข:
var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000))
แก้ไข
Chrome 25.0.1364.160
Firefox 20.0
พลาดการทดสอบที่สำคัญที่สุด (อย่างน้อยสำหรับฉัน): การทดสอบ Node.js ฉันสงสัยว่าใกล้กับเกณฑ์มาตรฐานของ Chrome
_.range(0, length - 1, 0);
หรือถ้าคุณมีอาร์เรย์อยู่แล้วและคุณต้องการอาร์เรย์ที่มีความยาวเท่ากัน
array.map(_.constant(0));
_.range(0, length, 0)
เชื่อ Lodash ไม่รวมค่าสิ้นสุด
[...new Array(5)].map(x => 0); // [0, 0, 0, 0, 0]
ในฐานะของECMAScript2016มีตัวเลือกหนึ่งที่ชัดเจนสำหรับอาร์เรย์ขนาดใหญ่
เนื่องจากคำตอบนี้ยังปรากฏใกล้ด้านบนสุดของการค้นหาของ Google นี่คือคำตอบสำหรับปี 2017
ต่อไปนี้เป็นjsbenchปัจจุบันที่มีวิธีการที่ได้รับความนิยมไม่กี่โหล หากคุณพบวิธีที่ดีกว่าโปรดเพิ่มแยกและแบ่งปัน
ฉันต้องการที่จะทราบว่าไม่มีจริงวิธีที่มีประสิทธิภาพที่สุดในการสร้างอาร์เรย์ที่เต็มไปด้วยความยาวเป็นศูนย์โดยพลการ คุณสามารถปรับให้เหมาะสมสำหรับความเร็วหรือเพื่อความชัดเจนและการบำรุงรักษา - สามารถพิจารณาตัวเลือกที่มีประสิทธิภาพมากขึ้นขึ้นอยู่กับความต้องการของโครงการ
เมื่อปรับให้เหมาะสมกับความเร็วคุณต้องการ: สร้างอาร์เรย์โดยใช้ไวยากรณ์ตามตัวอักษร ตั้งค่าความยาวเริ่มต้นการวนซ้ำตัวแปรและวนซ้ำผ่านอาร์เรย์โดยใช้ลูป while นี่คือตัวอย่าง
const arr = [];
arr.length = 120000;
let i = 0;
while (i < 120000) {
arr[i] = 0;
i++;
}
การติดตั้งอื่นที่เป็นไปได้คือ:
(arr = []).length = n;
let i = 0;
while (i < n) {
arr[i] = 0;
i++;
}
แต่ฉันไม่แนะนำให้ใช้การฝังครั้งที่สองในทางปฏิบัติเนื่องจากมีความชัดเจนน้อยกว่าและไม่อนุญาตให้คุณรักษาการบล็อกการกำหนดขอบเขตบนตัวแปรอาร์เรย์ของคุณ
สิ่งเหล่านี้เร็วกว่าการเติมด้วยห่วงอย่างมีนัยสำคัญและเร็วกว่าวิธีมาตรฐานประมาณ 90%
const arr = Array(n).fill(0);
แต่วิธีการเติมนี้ยังคงเป็นตัวเลือกที่มีประสิทธิภาพมากที่สุดสำหรับอาร์เรย์ขนาดเล็กเนื่องจากความชัดเจนกระชับและบำรุงรักษา ความแตกต่างด้านประสิทธิภาพจะไม่ฆ่าคุณจนกว่าคุณจะสร้างอาร์เรย์จำนวนมากที่มีความยาวตามลำดับเป็นพันหรือมากกว่า
บันทึกย่อที่สำคัญอื่น ๆ คู่มือสไตล์ส่วนใหญ่แนะนำให้คุณไม่ใช้อีกต่อไปvar
โดยไม่มีเหตุผลพิเศษเมื่อใช้ ES6 หรือใหม่กว่า ใช้const
สำหรับตัวแปรที่จะไม่ถูกนิยามใหม่และlet
สำหรับตัวแปรที่จะ MDNและคู่มือสไตล์ของ Airbnbเป็นสถานที่ที่ดีที่จะไปสำหรับข้อมูลเพิ่มเติมเกี่ยวกับการปฏิบัติที่ดีที่สุด คำถามไม่ได้เกี่ยวกับไวยากรณ์ แต่สิ่งสำคัญคือผู้คนใหม่ ๆ ที่ JS ต้องรู้เกี่ยวกับมาตรฐานใหม่เหล่านี้เมื่อทำการค้นหารีมคำตอบเก่าและใหม่
เพื่อสร้าง Array ใหม่ทั้งหมด
new Array(arrayLength).fill(0);
เพื่อเพิ่มค่าบางอย่างในตอนท้ายของ Array ที่มีอยู่
[...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)]);
ไม่เห็นวิธีนี้ในคำตอบดังนั้นนี่คือ:
"0".repeat( 200 ).split("").map( parseFloat )
ดังนั้นคุณจะได้รับอาร์เรย์ที่มีค่าเป็นศูนย์ความยาว 200:
[ 0, 0, 0, 0, ... 0 ]
ฉันไม่แน่ใจเกี่ยวกับประสิทธิภาพของรหัสนี้ แต่มันไม่ควรเป็นปัญหาถ้าคุณใช้มันสำหรับอาร์เรย์ที่ค่อนข้างเล็ก
นี้concat
รุ่นได้เร็วขึ้นมากในการทดสอบของฉันบน Chrome (2013/03/21) ประมาณ 200ms สำหรับ 10,000,000 องค์ประกอบ vs 675 สำหรับ init แบบตรง
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));
}
โบนัส:ถ้าคุณต้องการเติมอาเรย์ของคุณด้วยสตริงนี่เป็นวิธีรัดกุมในการทำ (ไม่เร็วอย่างที่คิดconcat
):
function filledArrayString(len, value) {
return new Array(len+1).join(value).split('');
}
ฉันกำลังทดสอบคำตอบที่ยอดเยี่ยมโดย TJ Crowder และเกิดการรวมเวียนซ้ำตามโซลูชัน concat ที่มีประสิทธิภาพสูงกว่าการทดสอบของเขาใน Chrome (ฉันไม่ได้ทดสอบเบราว์เซอร์อื่น)
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;
},
makeRec(29)
เรียกวิธีการที่มี
มันอาจจะมีมูลค่าการชี้ให้เห็นว่าArray.prototype.fill
ได้รับการเพิ่มเป็นส่วนหนึ่งของECMAScript 6 (Harmony) ข้อเสนอ ฉันอยากไปกับ polyfill ที่เขียนด้านล่างก่อนที่จะพิจารณาตัวเลือกอื่น ๆ ที่กล่าวถึงในเธรด
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;
};
}
สั้นที่สุดสำหรับลูปโค้ด
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;
รุ่น var ที่ปลอดภัย
var a=[],i=0;for(;i<100;)a[i++]=0;
edit:
for(var i=100,a=[];i--;)a[i]=0;
n
จะสั้นกว่านี้:for(var a=[];n--;a[n]=0);
let filled = [];
filled.length = 10;
filled.fill(0);
console.log(filled);
ฟังก์ชั่นที่เร็วที่สุดของฉันคือ:
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
การใช้ Native Push and Shift เพื่อเพิ่มรายการในอาเรย์นั้นเร็วกว่ามาก (ประมาณ 10 เท่า) กว่าการประกาศขอบเขตอาเรย์และอ้างอิงแต่ละไอเท็มเพื่อกำหนดค่าของมัน
fyi: ฉันได้รับเวลาเร็วขึ้นอย่างต่อเนื่องกับลูปแรกซึ่งนับถอยหลังเมื่อใช้งานใน firebug (ส่วนขยาย 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
ฉันสนใจที่จะรู้ว่า TJ Crowder ทำอะไรได้บ้าง? :-)
while (len--)
.. ใช้เวลาในการประมวลผลของฉันจากประมาณ 60 มิลลิวินาทีเป็นประมาณ 54 มิลลิเซคอน
ฉันรู้ว่าฉันมีโปรโตนี่ที่ไหนสักแห่ง :)
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);
แก้ไข: การทดสอบ
ในการตอบสนองต่อโจชัวและวิธีอื่น ๆ ฉันใช้การเปรียบเทียบของตัวเองและฉันเห็นผลลัพธ์ที่แตกต่างอย่างสิ้นเชิงกับที่รายงาน
นี่คือสิ่งที่ฉันทดสอบ:
//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();
ผล:
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
ดังนั้นโดยการกดการคำนวณของฉันช้าลงโดยทั่วไป แต่ทำงานได้ดีขึ้นด้วยอาร์เรย์ที่ยาวขึ้นใน FF แต่แย่กว่านั้นใน IE ซึ่งแย่ลงโดยทั่วไป
b = []...
) เร็วกว่า 10-15% แรก แต่ก็ช้ากว่าคำตอบของ Joshua มากกว่า 10 เท่า
else {this.length=n;}
หลังจากthis.length
-check นี้จะร่นอาร์เรย์ที่มีอยู่แล้วในกรณีที่จำเป็นเมื่ออีกinit
-ialising n
มันมีความยาวแตกต่างกัน
ฟังก์ชั่นไม่ระบุชื่อ:
(function(n) { while(n-- && this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
สั้นลงเล็กน้อยด้วย for-loop:
(function(n) { for(;n--;this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
ทำงานร่วมกับใด ๆเพียงแค่เปลี่ยนสิ่งที่อยู่ภายในObject
this.push()
คุณสามารถบันทึกฟังก์ชั่น:
function fill(size, content) {
for(;size--;this.push(content));
return this;
}
เรียกมันว่าใช้:
var helloArray = fill.call([], 5, 'hello');
// => ['hello', 'hello', 'hello', 'hello', 'hello']
การเพิ่มองค์ประกอบให้กับอาร์เรย์ที่มีอยู่แล้ว:
var helloWorldArray = fill.call(helloArray, 5, 'world');
// => ['hello', 'hello', 'hello', 'hello', 'hello', 'world', 'world', 'world', 'world', 'world']
ประสิทธิภาพการทำงาน: http://jsperf.com/zero-filled-array-creation/25