วิธีที่มีประสิทธิภาพมากที่สุดในการสร้างอาร์เรย์ JavaScript ที่เติมเต็มเป็นศูนย์หรือไม่


602

วิธีที่มีประสิทธิภาพที่สุดในการสร้างอาร์เรย์ที่เติมเต็มความยาวเป็นศูนย์ใน JavaScript คืออะไร?


7
ข้อมูลจริงบางอย่างเกี่ยวกับเรื่องนี้: jsperf.com/zeroarrayjs
Web_Designer

7
การเติม ES6อนุญาตให้ทำสิ่งนี้ได้โดยกำเนิด
Salvador Dali

1
arr = อาร์เรย์ใหม่ (ความยาว + 1) .joint (อักขระ) .split ('');
Jordan Stefanelli

4
อัพเดท 2016 : มาตรฐานที่กำหนดเองอื่นที่นี่: jsfiddle.net/basickarl/md5z0Lqq
K - ความเป็นพิษใน SO กำลังเพิ่มขึ้น

1
let i = 0; Array.from(Array(10), ()=>i++);
Bart Hoekstra

คำตอบ:


543

Array.prototype.fillแนะนำ ES6 มันสามารถใช้เช่นนี้:

new Array(len).fill(0);

ไม่แน่ใจว่ามันเร็ว แต่ฉันชอบเพราะสั้นและอธิบายตัวเองได้

ก็ยังคงไม่ได้อยู่ใน IE ( เข้ากันได้ตรวจสอบ ) แต่มีpolyfill ใช้ได้


15
เติมเร็ว new Array(len)ช้าลงอย่างเจ็บปวด (arr = []).length = len; arr.fill(0);เป็นเรื่องเกี่ยวกับวิธีแก้ปัญหาที่เร็วที่สุด ive เห็นได้ทุกที่ ... หรืออย่างน้อยก็ผูก
Pimp Trizkit

7
@PimpTrizkit arr = Array(n)และ(arr = []).length = nทำงานเหมือนกันตามข้อมูลจำเพาะ ในการใช้งานบางอย่างอาจเร็วขึ้น แต่ฉันไม่คิดว่าจะมีความแตกต่างใหญ่
Oriol

2
ฉันเริ่มการทดสอบด้วยอาร์เรย์หลายมิติและดูเหมือนว่าจะเพิ่มความเร็วในกรณีทดสอบของฉันอย่างมาก ตอนนี้เพิ่งทำการทดสอบเพิ่มเติมเกี่ยวกับ FF41 และ Chrome45.0.2454.99 m ใช่ฉันคิดว่าฉันต้องการพื้นที่เพิ่มเติมเพื่ออธิบายตัวเอง การทดสอบส่วนใหญ่ของฉันคืออคติที่ฉันจะยอมรับ แต่ลองดูนี่สิ ทำนายค่า var และใช้เพียงแค่บรรทัดนี้(arr = []).length = 1000; เทียบกับarr = new Array(1000);ความเร็วทดสอบทั้งใน Chrome และ FF ... newมันช้ามาก ทีนี้สำหรับความยาวของอาเรย์ที่น้อยกว่า .. พูด <50 หรือประมาณนั้น ... new Array()ดูเหมือนว่าจะทำงานได้ดีขึ้น แต่ ..
Pimp Trizkit

4
... ฉันจะยอมรับว่าฉันพลาดส่วนนี้ ... เมื่อฉันเพิ่มบรรทัดที่สองในการทดสอบ ... arr.fill(0) ... การเปลี่ยนแปลงทุกอย่างเรียงลำดับ ตอนนี้การใช้งานnew Array()จะเร็วขึ้นในกรณีส่วนใหญ่ยกเว้นเมื่อคุณไปถึงขนาดอาร์เรย์> 100000 ... จากนั้นคุณสามารถเริ่มเห็นการเพิ่มความเร็วอีกครั้ง แต่ถ้าคุณไม่จำเป็นต้องเติมมันด้วยศูนย์และสามารถใช้อาร์เรย์ที่มีความไม่แน่นอนของอาร์เรย์ว่างได้ จากนั้น(arr = []).length = xจะบ้าเร็วในกรณีทดสอบของฉันเกือบตลอดเวลา
Pimp Trizkit

4
โปรดทราบว่าในการวนซ้ำอาร์เรย์ (เช่น map หรือ forEach) ค่าจะต้องถูกตั้งค่ามิฉะนั้นจะข้ามดัชนีเหล่านั้น ค่าที่คุณตั้งไว้อาจเป็นสิ่งที่คุณต้องการ - แม้ไม่ได้กำหนด ตัวอย่าง: ลองเทียบกับnew Array(5).forEach(val => console.log('hi')); new Array(5).fill(undefined).forEach(val => console.log('hi'));
ArneHugo

387

แม้ว่านี่จะเป็นเธรดเก่า แต่ฉันต้องการเพิ่ม 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]

6
คำตอบที่ดี! คุณช่วยอธิบายกลอุบายด้วยได้Array.apply(null, new Array(5)).map(...)มั้ย สาเหตุเพียงทำ (อาร์เรย์ใหม่ (5)). แผนที่ (... ) จะไม่ทำงานตามที่สเป็คบอก
Dmitry Pashkevich

36
(BTW, เราไม่ได้จริงๆต้อง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...}map01apply
zertosh

4
พารามิเตอร์แรกสำหรับ.applyคือสิ่งที่คุณต้องการthisให้เป็น สำหรับวัตถุประสงค์เหล่านี้thisไม่สำคัญ - เราใส่ใจเฉพาะเกี่ยวกับการแพร่กระจายพารามิเตอร์ "คุณสมบัติ" ของ.apply- ดังนั้นจึงสามารถเป็นค่าใด ๆ ฉันชอบnullเพราะมันราคาถูกคุณอาจไม่ต้องการใช้{}หรือ[]เพราะคุณกำลังยกวัตถุให้โดยไม่มีเหตุผล
zertosh

2
นอกจากนี้ยังเริ่มต้นด้วยขนาด + กำหนดเร็วกว่าการผลัก ดูกรณีทดสอบjsperf.com/zero-fill-2d-array
Colin

2
สิ่งที่เกี่ยวกับ Array.apply (null, Array (5)). map (x => 0) สั้นกว่านิดหน่อย!
Arch Linux Tux

97

วิธีที่สวยงามในการเติมอาร์เรย์ด้วยค่าที่คำนวณล่วงหน้า

นี่เป็นอีกวิธีในการใช้ 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]

คำตอบโบนัส: เติมอาร์เรย์โดยใช้ String 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]

เคล็ดลับห้องนั่งเล่นมากมายในการโพสต์นั้น แต่หวังว่าจะไม่มีใครสามารถเข้าถึงรหัสการผลิตได้ :)
Eric Grange

แม้ว่าrepeatเคล็ดลับจะไม่ต้องการในการผลิตแน่นอนArray.from()ดี :-) อย่างสมบูรณ์แบบ
ลูซิโอ Paiva

ไม่จริง Array.from () นี่คือการสร้างอาร์เรย์โดยวนซ้ำโดยใช้ map () เรียกใช้ฟังก์ชันในแต่ละรายการเพื่อสร้างอาร์เรย์ใหม่จากนั้นจึงทิ้งอาร์เรย์แรก ... สำหรับอาร์เรย์ขนาดเล็กอาจเป็น ไร้เดียงสาสำหรับอาร์เรย์ที่ใหญ่กว่านี่เป็นรูปแบบที่ส่งผลให้ผู้คนที่เรียกเบราว์เซอร์ "memory hogs" :)
Eric Grange

ผู้ที่เกี่ยวข้องกับอาร์เรย์ขนาดใหญ่ควรรู้ดีกว่านี้อย่างแน่นอน สำหรับแอปทั่วไปการสร้างอาร์เรย์ aux ขนาดปกติ (สูงถึง 10k องค์ประกอบ) ที่จะถูกกำจัดในทันทีนั้นใช้ได้อย่างสมบูรณ์แบบ (ใช้ระยะเวลาเท่ากับว่าคุณหลีกเลี่ยงการสร้างอาร์เรย์พิเศษ - ทดสอบด้วย Chrome ล่าสุด) สำหรับกรณีเช่นนี้ความสามารถในการอ่านมีความสำคัญมากกว่าการปรับประสิทธิภาพให้เล็กที่สุด เกี่ยวกับเวลา O (n) จำเป็นถ้าคุณจำเป็นต้องคำนวณสิ่งที่แตกต่างกันสำหรับแต่ละองค์ประกอบ (หัวข้อหลักของคำตอบของฉัน) การสนทนานี้น่าสนใจมากดีใจที่คุณยกมันขึ้นมา!
Lucio Paiva

88

ในระยะสั้น

ทางออกที่เร็วที่สุด

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 ฉันทดสอบโซลูชันที่เลือกสำหรับกรณีทดสอบสองกรณี

  • อาร์เรย์ขนาดเล็ก - มี 10 องค์ประกอบ - คุณสามารถทำการทดสอบ นี่
  • อาร์เรย์ขนาดใหญ่ - พร้อมองค์ประกอบ 1M - คุณสามารถทำการทดสอบได้ที่นี่

สรุปผลการวิจัย

  • วิธีการแก้ปัญหาขึ้นอยู่กับ 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

ป้อนคำอธิบายรูปภาพที่นี่


เพิ่งรันการทดสอบบางอย่างบน Chrome 77 และการวนรอบแบบง่ายๆด้วย push () เร็วกว่าการเติมสองเท่า () ... ฉันสงสัยว่าผลข้างเคียงของการเติม () ละเอียดอ่อนเพียงใดป้องกันการใช้งานที่มีประสิทธิภาพมากขึ้น?
Eric Grange

@EricGrange ฉันอัปเดตคำตอบ - ที่ด้านล่างฉันอัปเดตลิงก์ไปที่ benchamrk พร้อมข้อเสนอของคุณ: กรณี P let a=[]; for(i=n;i--;) a.push(0);- แต่ช้ากว่า 4x fill(0)- ดังนั้นฉันจะไม่อัปเดตรูปภาพแม่มดในกรณีนั้น
Kamil Kiełczewski

2
การวัดที่ดี การวิเคราะห์: G ช้าเนื่องจากการปรับขนาดอาร์เรย์ทุกการวนซ้ำและการปรับขนาดหมายถึงทำการจัดสรรหน่วยความจำใหม่ A, B, M รวดเร็วเพราะการปรับขนาดทำได้เพียงครั้งเดียว +1
Roland

นี่เป็นหนึ่งในคำตอบไม่กี่ข้อที่พยายามตอบคำถามที่ถาม Unfornately มันล้มเหลวโดยการเกาะในเนื้อหาที่ไม่ใช่คำตอบและหายไปคำตอบที่แท้จริงที่เร็วที่สุดอย่างน้อยในมิถุนายน 2020 a = new Array(n); for (let i = 0; i < n; ++i) a[i] = 0;ทั่วทุกเบราว์เซอร์ซึ่งเป็นเป็น ทดสอบ
gman

@gman จริง ๆ แล้วคุณถูกต้อง - ฉันไม่เข้าใจว่าฉันจะพลาดได้อย่างไร - ฉันทำการทดสอบใหม่และอัปเดตคำตอบพร้อมรายละเอียดเพิ่มเติม - ขอบคุณ :)
Kamil Kiełczewski

63

วิธีการเติม ES 6 ที่กล่าวถึงแล้วจะดูแลเรื่องนี้เป็นอย่างดี เบราว์เซอร์เดสก์ท็อปที่ทันสมัยส่วนใหญ่สนับสนุนวิธีแบบ Array ต้นที่ต้องการแล้วในปัจจุบัน (Chromium, FF, Edge และ Safari) [ 1 ] คุณสามารถดูรายละเอียดเกี่ยวกับMDN ตัวอย่างการใช้งานที่เรียบง่ายคือ

a = new Array(10).fill(0);

เมื่อได้รับการสนับสนุนเบราว์เซอร์ปัจจุบันคุณควรใช้ความระมัดระวังหากคุณไม่แน่ใจว่าผู้ชมของคุณใช้เบราว์เซอร์เดสก์ท็อปที่ทันสมัย


4
หากคุณกรอกประเภทการอ้างอิงจะเป็นการอ้างอิงแบบเดียวกันกับทุกประเภท ใหม่ Array (10) .fill (null) .map (() => []) จะเป็นวิธีรวบรัดที่จะหลีกเลี่ยงสิ่งนี้ (เผาฉันในตอนแรกฮ่าฮ่า)
John Culviner

4
อัปเดตปี 2559 : วิธีนี้จะพัดทุกอย่างออกจากน้ำคลิกที่นี่เพื่อดูมาตรฐาน: jsfiddle.net/basickarl/md5z0Lqq
K - ความเป็นพิษใน SO กำลังเพิ่มขึ้น

มันจะใช้งานได้สำหรับอาร์เรย์ a = Array(10).fill(null).map(() => { return []; });
แอนดี้

2
@AndrewAnthonyGerst Terser:a = Array(10).fill(0).map( _ => [] );
Phrogz

50

หมายเหตุเพิ่มสิงหาคม 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>

ไม่แน่ใจว่าการกรอกข้อมูลย้อนหลังจะเกิดขึ้นที่นี่เนื่องจากคุณเป็นเพียงการเข้าถึงองค์ประกอบ (ไม่ได้ลบองค์ประกอบ) และคุณได้จัดสรรไว้ล่วงหน้าแล้ว ฉันผิดหรือเปล่า?
Triptych

จุดเติมด้านหลังนั้นไม่ได้เกี่ยวข้องกับอาเรย์โดยเฉพาะอย่างยิ่งมันเกี่ยวข้องกับเงื่อนไขการหลบหนีในขณะที่ 0 falsey ยุติการวนลูปอย่างมีประสิทธิภาพมาก
annakata

( แต่ผมได้สังเกตเห็นเพียงรหัสนี้ไม่จริงทำให้การใช้งานนั้น)
annakata

@annakata คุณไม่สามารถใช้สิ่งนี้ได้ที่นี่เพราะ 0 เป็นดัชนีที่ถูกต้อง
Triptych

@triptych: ไม่จริงทั้งหมดก็เป็นคำสั่งที่ถูกต้อง - ดูโพสต์ของฉัน
annakata

34

โดยค่าเริ่มต้นUint8Array, Uint16ArrayและUint32Arrayชั้นเรียนให้ศูนย์เป็นค่าของตนเพื่อให้คุณไม่จำเป็นต้องกรอกข้อมูลใด ๆ เทคนิคที่ซับซ้อนเพียงแค่ทำ:

var ary = new Uint8Array(10);

องค์ประกอบทั้งหมดของอาร์เรย์aryจะเป็นศูนย์โดยค่าเริ่มต้น


5
นี้เป็นสิ่งที่ดี แต่ทราบใจนี้จะไม่สามารถได้รับการปฏิบัติเช่นเดียวกับอาร์เรย์ปกติเช่นเป็นArray.isArray(ary) falseความยาวเป็นแบบอ่านอย่างเดียวดังนั้นคุณจึงไม่สามารถผลักรายการใหม่ ๆ ไปได้เช่นเดียวกับary.push
MusikAnimal

Fwiw อาร์เรย์ที่พิมพ์ทั้งหมดเก็บไว้0เป็นค่าเริ่มต้น
jfunk

2
@MusikAnimal Array.from(new Uint8Array(10))จะให้อาร์เรย์ปกติ
Tomas Langkaas

@TomasLangkaas: ใช่ แต่คำตอบอีกข้อหนึ่งแสดงให้เห็นว่านั่นช้ากว่าArray(n).fill(0)ใน Chrome ประมาณ 5 เท่าถ้าสิ่งที่คุณต้องการจริงๆคือ JS Array หากคุณสามารถใช้ TypedArray นี้เป็นได้เร็วขึ้นมากแม้กว่าแต่โดยเฉพาะอย่างยิ่งถ้าคุณสามารถใช้ค่าเริ่มต้นการเริ่มต้นค่าของ.fill(0) 0ดูเหมือนจะไม่มีคอนสตรัคเตอร์ที่ใช้ค่าเติมและความยาวตามที่ C ++ std::vectorมี ดูเหมือนว่าค่าที่ไม่เป็นศูนย์ใด ๆ ที่คุณต้องสร้าง TypedArray ที่มีค่าศูนย์แล้วเติมให้เต็ม : /
Peter Cordes

29

ถ้าคุณใช้ 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]

23
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ฯลฯ


3
ไม่ได้เป็นiภายนอกตัวแปรท้องถิ่น? lengthถูกส่งผ่านโดยค่าดังนั้นคุณควรจะสามารถลดได้โดยตรง
ฌอนสดใส

3
แม้ว่าจะดูดีในตอนแรก แต่น่าเสียดายที่มันช้ามากในการกำหนดค่า ณ จุดใด ๆ ในอาเรย์ (เช่นarr[i] = value) arr.push(value)มันมากเร็วกว่าที่จะห่วงผ่านตั้งแต่ต้นจนจบและการใช้งาน มันน่ารำคาญเพราะฉันชอบวิธีการของคุณ
Nick Brunt

19

ใช้สัญกรณ์วัตถุ

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 = [];

จะมีการดัดแปลงต้นแบบเหล่านั้น

ฉันจะไม่กังวลกับประสิทธิภาพหรือความเร็วของการดำเนินการมากเกินไปมีหลายสิ่งหลายอย่างที่คุณน่าจะทำซึ่งมีความสิ้นเปลืองและมีราคาแพงกว่าการติดตั้งความยาวโดยพลการที่มีเลขศูนย์


5
เอ่อ ... ไม่มีnullในอาร์เรย์นี้ -var x = new Array(7);
kangax

5
ที่จริงแล้วอาร์เรย์ไม่ได้เต็มไปด้วยสิ่งใดด้วย Array (n) ใหม่ไม่ใช่แม้แต่ 'undefined' มันแค่ตั้งค่าความยาวของอาร์เรย์เป็น n คุณสามารถตรวจสอบสิ่งนี้ได้โดยโทร (อาร์เรย์ใหม่ (1)) forEach (... ) forEach ไม่เคยดำเนินการซึ่งแตกต่างจากถ้าคุณเรียกมันใน [undefined]
JussiR

4
new Array(7)ไม่ได้สร้างอาร์เรย์ "เต็มไปด้วยไม่ได้กำหนด" มันสร้างอาร์เรย์ว่างเปล่าที่มีความยาว 7
RobG

1
คุณอาจต้องการที่จะพิจารณาในส่วนของคำตอบของคุณเป็นสิ่งที่ @RobG ไม่ว่าจะเป็นสิ่งสำคัญ (ถ้าสิ่งที่คุณกำลังพูดเป็นความจริงการทำแผนที่จะได้รับง่ายมาก)
Abdo

1
(new Array(10)).fill(0)วันนี้คุณสามารถทำ
Javier de la Rosa

18

ฉันได้ทดสอบการรวมกันของการจัดสรรล่วงหน้า / ไม่จัดสรรล่วงหน้านับรวมขึ้น / ลงและ / ในขณะที่ลูปใน 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;
}

1
คุณสามารถโยนvar array = []คำแถลงลงในส่วนแรกของ for loop ได้โดยคั่นด้วยเครื่องหมายจุลภาคเท่านั้น
damianb

ฉันชอบคำแนะนำของ damianb แต่อย่าลืมมอบหมายและเครื่องหมายจุลภาคก่อนการเพิ่ม! `สำหรับ (var i = 0; i <length; array [i] = val, i ++);
punstress

ทำสิ่งที่คนอื่นคิดถึงคุณเป็นอันดับสองและตั้งค่าความยาวของอาร์เรย์เป็นlengthค่าที่กำหนดไว้เพื่อไม่ให้เปลี่ยนแปลงตลอดเวลา นำอาร์เรย์ความยาว 1 ล้านศูนย์จาก 40ms เป็น 8 ในเครื่องของฉัน
Jonathan Grey

ฉันดูเหมือนจะได้รับความเร็วเพิ่มขึ้น 10-15% เมื่อฉันปรับโครงสร้างโซลูชันนี้เป็นหนึ่งซับ 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ดูเหมือนว่าจะเร็วกว่าในรุ่นนี้)
Pimp Trizkit

ฉันจะทราบว่าในการทดสอบของฉัน ในจำนวนที่เหมาะสมของกรณีทดสอบของฉัน, รุ่นสุดท้ายข้างต้นดูเหมือนว่าจะดำเนินการ 3x เร็วกว่าถึง 10 เท่า ... ฉันไม่แน่ใจว่าทำไม ... (ขนาดอาร์เรย์ที่แตกต่างกันทดสอบระหว่างโครเมี่ยมและ FF)
Pimp Trizkit

13

หากคุณต้องการสร้างอาร์เรย์ที่เติมศูนย์จำนวนมากที่มีความยาวต่างกันระหว่างการประมวลผลโค้ดของคุณวิธีที่เร็วที่สุดที่ฉันพบเพื่อบรรลุเป้าหมายนี้คือการสร้างอาร์เรย์ศูนย์หนึ่งครั้งโดยใช้วิธีใดวิธีหนึ่งที่กล่าวถึงในหัวข้อนี้ ที่คุณรู้ว่าจะไม่มีวันเกินจากนั้นหั่นส่วนนั้นตามความจำเป็น

ตัวอย่างเช่น (ใช้ฟังก์ชั่นจากคำตอบที่เลือกไว้ด้านบนเพื่อเริ่มต้นอาร์เรย์) สร้างอาร์เรย์ที่เต็มไปด้วยความยาวmaxLength แบบศูนย์ซึ่งเป็นตัวแปรที่มองเห็นได้จากโค้ดที่ต้องใช้ศูนย์อาร์เรย์:

var zero = newFilledArray(maxLength, 0);

ตอนนี้ฝานอาร์เรย์นี้ทุกครั้งที่คุณต้องการอาเรย์ที่เต็มไปด้วยความยาวที่ต้องการความยาวความยาว< maxLength :

zero.slice(0, requiredLength);

ฉันกำลังสร้างอาร์เรย์ที่กรอกข้อมูลเป็นศูนย์เป็นพัน ๆ ครั้งในระหว่างการประมวลผลโค้ดของฉันซึ่งทำให้กระบวนการเร็วขึ้นอย่างมาก


13
function zeroFilledArray(size) {
    return new Array(size + 1).join('0').split('');
}

3
คุณอาจใช้new Array(size+1).join("x").split("x").map(function() { return 0; })เพื่อรับตัวเลขจริง
Yuval

6
@Yuval หรือเพียงแค่new Array(size+1).join('0').split('').map(Number)
Paul

11

ฉันไม่มีอะไรกับ:

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]


10

วิธีที่ฉันมักจะทำมัน (และเป็นไปอย่างรวดเร็วที่น่าตื่นตาตื่นใจ) 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

  1. Frederik Gottlieb - 6.43
  2. Sam Barnum - 4.83
  3. อีไล - 3.68
  4. โจชัว 2.91
  5. Mathew Crumley - 2.67
  6. bduran - 2.55
  7. ข้าวอัลเลน - 2.11
  8. Kangax - 0.68
  9. Tj Crowder - 0.67
  10. zertosh - ข้อผิดพลาด

Firefox 20.0

  1. ข้าวอัลเลน - 1.85
  2. โจชัว - 1.82
  3. Mathew Crumley - 1.79
  4. bduran - 1.37
  5. Frederik Gottlieb - 0.67
  6. Sam Barnum - 0.63
  7. อีไล - 0.59
  8. kagax - 0.13
  9. Tj Crowder - 0.13
  10. zertosh - ข้อผิดพลาด

พลาดการทดสอบที่สำคัญที่สุด (อย่างน้อยสำหรับฉัน): การทดสอบ Node.js ฉันสงสัยว่าใกล้กับเกณฑ์มาตรฐานของ Chrome


นี่เป็นวิธีที่มีประสิทธิภาพมากที่สุดสำหรับนิ้วมือของฉันและต่อตาของฉัน แต่มันช้ามากสำหรับ Chrome (ตาม jsperf นั้นช้าลง 99%)
Orwellophile

1
ฉันสงสัยว่าปัญหาใน Mac ของเพื่อนคุณเกี่ยวข้องกับ: stackoverflow.com/questions/39129200/หรือมิฉะนั้น Array.slice ไม่จัดการ UInt8Array และรั่วหน่วยความจำที่ไม่ได้เตรียมไว้หรือไม่ (ปัญหาด้านความปลอดภัย!)
robocat

@robocat เยี่ยมมาก! ถ้าฉันจำได้ดีเราใช้ Node.js 0.6 หรือ 0.8 เราคิดถึงการรั่วไหลบางอย่าง แต่เราไม่สามารถสร้างมันขึ้นมาใหม่ด้วยสแต็คการผลิตดังนั้นเราจึงตัดสินใจไม่สนใจมัน
durum

10

ใช้lodashหรือขีดล่าง

_.range(0, length - 1, 0);

หรือถ้าคุณมีอาร์เรย์อยู่แล้วและคุณต้องการอาร์เรย์ที่มีความยาวเท่ากัน

array.map(_.constant(0));

ดีใจที่คุณเพิ่มคำตอบนี้เมื่อฉันใช้เครื่องหมายขีดล่างและฉันรู้ว่ามีบางอย่างสำหรับสิ่งนี้ ... แต่ยังไม่สามารถค้นหาได้ ฉันแค่หวังว่าฉันจะสามารถสร้างอาร์เรย์ของวัตถุโดยใช้สิ่งนี้
PandaWood

@PandaWood _.range (0, ความยาว -1, 0) .map (Object.new) ฉันคิดว่า
djechlin

ฉันควรจะ_.range(0, length, 0)เชื่อ Lodash ไม่รวมค่าสิ้นสุด
user4815162342


8

ในฐานะของ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 ต้องรู้เกี่ยวกับมาตรฐานใหม่เหล่านี้เมื่อทำการค้นหารีมคำตอบเก่าและใหม่


8

เพื่อสร้าง 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)]);


6

ไม่เห็นวิธีนี้ในคำตอบดังนั้นนี่คือ:

"0".repeat( 200 ).split("").map( parseFloat )

ดังนั้นคุณจะได้รับอาร์เรย์ที่มีค่าเป็นศูนย์ความยาว 200:

[ 0, 0, 0, 0, ... 0 ]

ฉันไม่แน่ใจเกี่ยวกับประสิทธิภาพของรหัสนี้ แต่มันไม่ควรเป็นปัญหาถ้าคุณใช้มันสำหรับอาร์เรย์ที่ค่อนข้างเล็ก


5
ไม่ว่าเร็วหรือสั้นที่สุด แต่ให้การสนับสนุนที่ดีกับความหลากหลายของโซลูชั่น
7vujy0f0hy


4

นี้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('');
}

2
ตกลงเถอะ นั่นคือวิธีที่เร็วกว่าการใช้ Array (len) ใหม่ แต่! ฉันเห็นใน Chrome ว่าการอ่านข้อมูลนั้นในภายหลังนั้นใช้เวลานานกว่ามาก นี่คือบางส่วนของการประทับเวลาเพื่อแสดงสิ่งที่ฉันหมายถึง: (ใช้อาร์เรย์ใหม่ (len)) 0.365: การทำอาร์เรย์ 4.526: การดำเนินการ Convolution 10.75: การดำเนินการ Convolution เสร็จสมบูรณ์ (โดยใช้ concat) 0.339: การทำ Array 0.591: Executioning Convolution // OMG Convolution Complete
Brooks

4

ฉันกำลังทดสอบคำตอบที่ยอดเยี่ยมโดย 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)เรียกวิธีการที่มี



4

มันอาจจะมีมูลค่าการชี้ให้เห็นว่า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;
  };
}

4

สั้นที่สุดสำหรับลูปโค้ด

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;

2
ระบุว่าความยาวเป็นตัวแปรที่กำหนดไว้ซึ่งnจะสั้นกว่านี้:for(var a=[];n--;a[n]=0);
Tomas Langkaas


3

ฟังก์ชั่นที่เร็วที่สุดของฉันคือ:

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 มิลลิเซคอน
nickf

คำตอบของ Matthew Crumbly ยังคงเต้นจริง (30ms)!
nickf

3

ฉันรู้ว่าฉันมีโปรโตนี่ที่ไหนสักแห่ง :)

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 เท่า
nickf

ฉันรู้ว่านี้คือการโพสต์โบราณ แต่บางทีมันก็ยังเป็นที่สนใจของคนอื่น (เช่นฉัน) ดังนั้นฉันอยากจะแนะนำ adition ให้กับฟังก์ชั่นต้นแบบ: รวมถึงelse {this.length=n;}หลังจากthis.length -check นี้จะร่นอาร์เรย์ที่มีอยู่แล้วในกรณีที่จำเป็นเมื่ออีกinit-ialising nมันมีความยาวแตกต่างกัน
cars10m

2

ฟังก์ชั่นไม่ระบุชื่อ:

(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]

ทำงานร่วมกับใด ๆเพียงแค่เปลี่ยนสิ่งที่อยู่ภายในObjectthis.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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.