วิธีสร้างอาร์เรย์ที่มี 1 … N


1163

ฉันกำลังมองหาทางเลือกด้านล่างเพื่อสร้างอาร์เรย์ JavaScript ที่มี 1 ถึง N โดยที่ N รู้จักเฉพาะในรันไทม์

var foo = [];

for (var i = 1; i <= N; i++) {
   foo.push(i);
}

สำหรับฉันมันรู้สึกว่าควรมีวิธีการทำเช่นนี้โดยไม่ต้องวน


224
หลังจากอ่านหน้านี้ทั้งหมดฉันได้ข้อสรุปว่าการวนลูปง่าย ๆ ของคุณนั้นง่ายที่สุดอ่านง่ายที่สุดและเกิดข้อผิดพลาดน้อยที่สุด
Kokodoko

หากใครต้องการบางสิ่งบางอย่างที่สูงขึ้นฉันสร้าง Node.js lib ที่ไม่นี้สำหรับตัวเลขตัวอักษร / ลบช่วงบวก ฯลฯgithub.com/jonschlinkert/fill-range มันใช้ในgithub.com/jonschlinkert/bracesสำหรับการขยายรั้งและgithub.com/jonschlinkert/micromatchสำหรับรูปแบบ glob
jonschlinkert

1
คุณควรแก้ไขเพื่อพูดว่า "วิธีสร้างอาร์เรย์ที่มีความยาว N" แทนที่จะเป็น "... ที่มี 1 ... N" ซึ่งหมายความว่าหลังจะมีองค์ประกอบที่มีค่า 1 ถึง N
Steven Landow

7
@StevenLand เหตุใด OP จึงควรเปลี่ยนชื่อ เขาต้องการอาร์เรย์ที่มีค่า1 ... Nหรือไม่
Andre Elrico

คำถามที่ดีชื่อที่ดีคำตอบที่โง่ (kinda)
Bitterblue

คำตอบ:


381

หากฉันได้สิ่งที่คุณต้องการคุณต้องการอาร์เรย์ของตัวเลข1..nที่คุณสามารถวนซ้ำในภายหลัง

หากนี่คือทั้งหมดที่คุณต้องการคุณสามารถทำสิ่งนี้แทนได้หรือไม่?

var foo = new Array(45); // create an empty array with length 45

จากนั้นเมื่อคุณต้องการใช้ ... (ยกเลิกการปรับให้เหมาะสมเช่น)

for(var i = 0; i < foo.length; i++){
  document.write('Item: ' + (i + 1) + ' of ' + foo.length + '<br/>'); 
}

เช่นถ้าคุณไม่ต้องการเก็บอะไรในอาเรย์คุณแค่ต้องการภาชนะที่มีความยาวที่เหมาะสมซึ่งคุณสามารถทำซ้ำได้ ... นี่อาจจะง่ายกว่า

ดูการทำงานได้ที่นี่: http://jsfiddle.net/3kcvm/


4
ประทับใจที่คุณจัดการกับวลีคำถามของฉันได้ดีกว่าที่คุณสามารถคุณถูกต้องตามที่สะท้อนทั้งหมดที่ฉันต้องการคืออาร์เรย์ของตัวเลขที่ฉันสามารถวนซ้ำในภายหลัง :) ขอบคุณสำหรับคำตอบของคุณ
Godders

147
@Godders: ถ้านี่คือสิ่งที่คุณกำลังมองหาทำไมคุณต้องมีอาร์เรย์? ง่ายvar n = 45;แล้ววนลูปจาก1..nจะทำ
casablanca

3
@Godders - หากต้องการทราบว่าคุณต้องการลดขนาดของอาเรย์หลังจากที่ถูกสร้างขึ้นให้มีความยาว M ให้ใช้foo.length = M--- ข้อมูลที่ถูกตัดออกไปจะหายไป ดูการทำงาน ==> jsfiddle.net/ACMXp
Peter Ajtai

24
ผมไม่ได้รับว่าทำไมคำตอบนี้ได้มี upvotes ... โดยเฉพาะอย่างยิ่งเมื่อ OP ตัวเองเห็นด้วยก็ไม่ได้ทำให้ความรู้สึกใด ๆ var n = 45;ในความคิดเห็นไม่กี่ข้างต้นตั้งแต่ที่เขาจะได้ทำเพียงแค่
plalx

72
@scunliffe: โปรดทราบว่าnew Array(45);จะไม่ "สร้างอาร์เรย์องค์ประกอบ 45" (ในความหมายเดียวกับที่[undefined,undefined,..undefined]ทำ) มันค่อนข้างจะ "สร้างอาร์เรย์ที่ว่างเปล่าที่มีความยาว = 45" ( [undefined x 45]) var foo = []; foo.length=45;เช่นเดียวกับ นั่นเป็นเหตุผลforEachและmapจะไม่ใช้ในกรณีนี้
tomalec

1307

ใน ES6 ใช้อาร์เรย์จาก ()และคีย์ ()วิธีการ

Array.from(Array(10).keys())
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

รุ่นที่สั้นกว่าโดยใช้ตัวดำเนินการสเปร

[...Array(10).keys()]
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

74
เพิ่งทราบนี้จะเริ่มต้นที่ 0 จะต้องเชื่อมโยงmapไปยังอาร์เรย์เพื่อปรับค่า ( [...Array(10).keys()].map(x => x++);) เพื่อเริ่มต้นที่ 1
สเตอร์ลิงอาร์เชอร์

32
การเปลี่ยนแปลงเพียงแค่map(x => x++)ไปmap(x => ++x)เนื่องจากมีความสำคัญเพิ่มขึ้นเกิดขึ้นหลังจากที่ผลตอบแทนค่า :)
บร็อค

93
เอ่ออะไร! ทำไมmapเมื่อคุณสามารถslice? [...Array(N+1).keys()].slice(1)
Robin

19
หรือไม่ใช้keysและมีเพียง 1 แผนที่ ->Array.from(Array(10)).map((e,i)=>i+1)
yonatanmn

60
หรือไม่ใช้คีย์และแผนที่และส่งผ่านฟังก์ชั่นการทำแผนที่ไปที่from Array.from(Array(10), (e,i)=>i+1)
Fabio Antunes

844

คุณสามารถทำได้:

var N = 10; 
Array.apply(null, {length: N}).map(Number.call, Number)

ผล: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

หรือด้วยค่าสุ่ม:

Array.apply(null, {length: N}).map(Function.call, Math.random)

ผล: [0.7082694901619107, 0.9572225909214467, 0.8586748542729765, 0.8653848143294454, 0.008339877473190427, 0.9911756622605026, 0.8133423360995948, 0.837758846580822, 0.857754289759, 0.85867485427864759, 0.85867485427,986,986,986,475,475,475,475,436,475 ผลลัพธ์

คำอธิบาย

ก่อนอื่นให้สังเกตว่าNumber.call(undefined, N)เทียบเท่ากับNumber(N)ซึ่งเพิ่งกลับNมา เราจะใช้ความจริงนั้นในภายหลัง

Array.apply(null, [undefined, undefined, undefined])เทียบเท่ากับArray(undefined, undefined, undefined)ซึ่งสร้างอาร์เรย์สามองค์ประกอบและกำหนดให้undefinedกับแต่ละองค์ประกอบ

คุณจะพูดถึงองค์ประกอบของN ได้อย่างไร? พิจารณาวิธีการArray()ทำงานซึ่งไปบางอย่างเช่นนี้:

function Array() {
    if ( arguments.length == 1 &&
         'number' === typeof arguments[0] &&
         arguments[0] >= 0 && arguments &&
         arguments[0] < 1 << 32 ) {
        return [  ];  // array of length arguments[0], generated by native code
    }
    var a = [];
    for (var i = 0; i < arguments.length; i++) {
        a.push(arguments[i]);
    }
    return a;
}

ตั้งแต่ ECMAScript 5 , Function.prototype.apply(thisArg, argsArray)ยังยอมรับวัตถุอาร์เรย์เหมือนเป็ดพิมพ์เป็นพารามิเตอร์ที่สอง ถ้าเราเรียกใช้Array.apply(null, { length: N })แล้วมันจะดำเนินการ

function Array() {
    var a = [];
    for (var i = 0; i < /* arguments.length = */ N; i++) {
        a.push(/* arguments[i] = */ undefined);
    }
    return a;
}

ตอนนี้เรามีNundefinedอาร์เรย์องค์ประกอบที่มีองค์ประกอบของแต่ละชุดจะ เมื่อเราเรียกมันแต่ละองค์ประกอบจะถูกตั้งเป็นผลมาจากการ.map(callback, thisArg) callback.call(thisArg, element, index, array)ดังนั้น[undefined, undefined, …, undefined].map(Number.call, Number)จะแมปองค์ประกอบแต่ละรายการ(Number.call).call(Number, undefined, index, array)ซึ่งเหมือนกับNumber.call(undefined, index, array)ที่เราสังเกตไว้ก่อนหน้านี้ซึ่งประเมินindexว่า ทำให้อาร์เรย์ที่มีองค์ประกอบเหมือนกับดัชนีเสร็จสมบูรณ์

ทำไมต้องเผชิญกับปัญหาArray.apply(null, {length: N})แทนที่จะเป็นเพียงแค่Array(N)? ท้ายที่สุดนิพจน์ทั้งสองจะส่งผลให้มีอาร์เรย์N -element ขององค์ประกอบที่ไม่ได้กำหนด ความแตกต่างคือในนิพจน์ก่อนหน้าแต่ละองค์ประกอบจะถูกตั้งค่าเป็นไม่ได้กำหนดอย่างชัดเจนในขณะที่องค์ประกอบหลังแต่ละองค์ประกอบไม่เคยถูกตั้งค่า ตามเอกสารของ.map():

callbackถูกเรียกเฉพาะสำหรับดัชนีของอาร์เรย์ที่มีค่าที่ได้รับมอบหมาย; มันไม่ได้ถูกเรียกใช้สำหรับดัชนีที่ถูกลบไปหรือที่ไม่เคยมีการกำหนดค่า

ดังนั้นจึงArray(N)ไม่เพียงพอ Array(N).map(Number.call, Number)จะส่งผลให้อาร์เรย์เตรียมความยาวN

ความเข้ากันได้

เนื่องจากเทคนิคนี้ขึ้นอยู่กับพฤติกรรมที่Function.prototype.apply()ระบุใน ECMAScript 5 มันจะไม่ทำงานในเบราว์เซอร์ pre-ECMAScript 5 เช่น Chrome 14 และ Internet Explorer 9


62
+1 สำหรับความฉลาด แต่โปรดทราบว่านี่เป็นคำสั่งของขนาด SLOWER กว่าแบบดั้งเดิมสำหรับลูป: jsperf.com/array-magic-vs-for
warpech

7
ฉลาดมาก - อาจเป็นเช่นนั้น การใช้ประโยชน์จากความจริงที่ว่าFunction.prototype.callพารามิเตอร์แรกคือthisวัตถุที่จะจับคู่โดยตรงกับArray.prototype.mapพารามิเตอร์ตัววนซ้ำของมันมีความหมายบางอย่าง
โนอาห์ไฟรตัส

14
นี่เป็นสิ่งที่ฉลาดจริงๆ (มีขอบเขตในการใช้ JS อย่างไม่เหมาะสม) ข้อมูลเชิงลึกที่สำคัญจริงๆที่นี่คือความแปลกประหลาดของmapค่านิยมที่ไม่ได้กำหนดในความคิดของฉัน อีกรุ่น (และอาจชัดเจนกว่าเล็กน้อยอีกต่อไปแม้ว่าจะนานกว่า) คือ: Array.apply(null, { length: N }).map(function(element, index) { return index; })
Ben Reich

6
@BenReich ดียิ่งขึ้น (ในแง่ของระดับการละเมิด JS): Array.apply(null, new Array(N)).map(function(_,i) { return i; }) หรือในกรณีของฟังก์ชั่น es6 และลูกศรยิ่งสั้นลง: Array.apply(null, new Array(N)).map((_,i) => i)
oddy

1
ถ้าสิ่งนี้คืนอาร์เรย์ที่เริ่มต้นที่ 1 มันจะตอบคำถามของ OP จริง ๆ
Hai Phan

482

หลายวิธีในการใช้ES6

การใช้ตัวดำเนินการ spread ( ...) และปุ่ม

[ ...Array(N).keys() ].map( i => i+1);

เติม / แผนที่

Array(N).fill().map((_, i) => i+1);

Array.from

Array.from(Array(N), (_, i) => i+1)

Array.from และ{ length: N }แฮ็ค

Array.from({ length: N }, (_, i) => i+1)

หมายเหตุเกี่ยวกับรูปแบบทั่วไป

ทุกรูปแบบข้างต้นอาร์เรย์สามารถผลิต initialised เป็นค่าที่ต้องการสวยมาก ๆ โดยการเปลี่ยนi+1การแสดงออกที่ต้องการ (เช่นi*2, -i, 1+i*2, i%2และอื่น ๆ ) หากการแสดงออกสามารถแสดงออกโดยฟังก์ชั่นบางอย่างfแล้วรูปแบบแรกกลายเป็นเพียง

[ ...Array(N).keys() ].map(f)

ตัวอย่าง:

Array.from({length: 5}, (v, k) => k+1); 
// [1,2,3,4,5]

เนื่องจากอาร์เรย์ถูกเตรียมใช้งานด้วยundefinedในแต่ละตำแหน่งค่าของv จะเป็นundefined

ตัวอย่างแสดงแบบฟอร์มทั้งหมด

ตัวอย่างทั่วไปเพิ่มเติมด้วยฟังก์ชั่นเริ่มต้นที่กำหนดเองfเช่น

[ ...Array(N).keys() ].map((i) => f(i))

หรือง่ายกว่า

[ ...Array(N).keys() ].map(f)


33
คำตอบที่ดีที่สุด IMHO ดูเพิ่มเติมdeveloper.mozilla.org/de/docs/Web/JavaScript/Reference/…
le_m

5
ใช้ k ++ สำหรับอาร์เรย์เริ่มต้นที่ 0
Borgboy

1
หากคุณต้องการที่เพิ่มขึ้นไม่ได้ใช้การใช้งานk++ ++k
อเล็กซ์

4
Beware Array.from ไม่ได้รับการสนับสนุนใน IE เว้นแต่ว่าคุณกำลังเติมโพลีไว้
Lauren

2
ในการทำให้คอมไพเลอร์ TS มีความสุขให้ลองแทนที่ param ที่ไม่ได้ใช้ด้วย lodash: Array.from ({length: 5}, (_, k) => k + 1);
Journeycorner

297

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


สิ่งนี้กล่าวว่าสำหรับความต้องการของคุณคุณอาจต้องการประกาศอาร์เรย์ที่มีขนาดที่แน่นอน:

var foo = new Array(N);   // where N is a positive integer

/* this will create an array of size, N, primarily for memory allocation, 
   but does not create any defined values

   foo.length                                // size of Array
   foo[ Math.floor(foo.length/2) ] = 'value' // places value in the middle of the array
*/


ES6

การแพร่กระจาย

การใช้ประโยชน์จากตัวดำเนินการสเปรด ( ...) และkeysวิธีการช่วยให้คุณสร้างอาร์เรย์ชั่วคราวขนาด N เพื่อสร้างดัชนีแล้วอาร์เรย์ใหม่ที่สามารถกำหนดให้กับตัวแปรของคุณ:

var foo = [ ...Array(N).keys() ];

เติม / แผนที่

คุณสามารถสร้างขนาดของอาร์เรย์ที่คุณต้องการก่อนเติมด้วย undefined แล้วสร้าง array ใหม่โดยใช้mapซึ่งจะตั้งค่าแต่ละองค์ประกอบเป็นดัชนี

var foo = Array(N).fill().map((v,i)=>i);

Array.from

สิ่งนี้ควรเริ่มต้นกับความยาวของขนาด N และใส่ข้อมูลอาเรย์ในครั้งเดียว

Array.from({ length: N }, (v, i) => i)



แทนความคิดเห็นและความสับสนหากคุณต้องการเก็บค่าจาก 1..N ในตัวอย่างด้านบนมีตัวเลือกสองอย่าง:

  1. หากดัชนีพร้อมใช้งานคุณสามารถเพิ่มได้ทีละหนึ่ง (เช่น, ++i)
  2. ในกรณีที่ไม่ได้ใช้ดัชนี - และอาจเป็นวิธีที่มีประสิทธิภาพมากขึ้น - คือการสร้างอาร์เรย์ของคุณ แต่ทำให้ N แทน N + 1 จากนั้นเลื่อนไปด้านหน้า

    ดังนั้นหากคุณต้องการ 100 หมายเลข:

    let arr; (arr=[ ...Array(101).keys() ]).shift()





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

ทำไมใครบางคนทำเช่นนี้คือให้มีอาร์เรย์ของตัวเลขเพื่อเติมรายการแบบหล่นลงโดยให้ผู้ใช้เลือกได้ตั้งแต่ 1 ถึง 10 อาร์เรย์เล็ก ๆ ด้วยมือ [1,2,3 ... 10] เข้าท่า แต่จะเกิดอะไรขึ้นถ้า มันมาจาก 1 ถึง 50? เกิดอะไรขึ้นถ้าหมายเลขท้ายเปลี่ยนแปลง?
CigarDoug

@CigarDoug ฉันไม่สงสัยเลยว่ามี usecase แต่ฉันเดาว่ามันมีขนาดเล็ก เหตุใดจึงต้องมีอาร์เรย์ของตัวเลขโดยทั่วไปเมื่อวนซ้ำอาร์เรย์จะใช้ดัชนีเป็นส่วนหนึ่งของการสร้างลูป - ไม่ว่าจะเป็นอาร์กิวเมนต์ของฟังก์ชันลูปหรือตัวแปรเคาน์เตอร์ - ดังนั้นการเก็บอาร์เรย์ของตัวเลขจึงดูเล็กน้อย เพื่อสร้างอาร์เรย์ของความกว้างที่ระบุหรือเพียงตัวแปรที่เก็บขอบเขตบนของอาร์เรย์ ฉันสามารถนึกถึงกรณีการใช้งานเพียงเล็กน้อย แต่ OP
vol7ron

4
อย่างที่ฉันบอกว่าฉันต้องเติมลงด้วยหมายเลข 1 ถึง 10 นั่นคือทั้งหมด มี usecase คือ usecase ของฉัน นั่นคือวิธีที่ฉันพบหน้านี้ ดังนั้นการสร้างอาเรย์ด้วยมือจึงมีความซับซ้อนน้อยกว่าสิ่งที่ฉันเห็นที่นี่ ดังนั้นความต้องการของฉันไม่ใช่ข้อกำหนดของ OP แต่ฉันมีคำตอบ
CigarDoug

1
@ vol7ron มี usecase ฉันยังมีอีก ในเชิงมุมในการแบ่งหน้าฉันต้องการแสดงหน้าในส่วนท้ายที่สามารถคลิกได้ ดังนั้นฉันจึงวนรอบองค์ประกอบในมุมมองด้วย * ngFor = "ให้ p ของ pagesCounter" คุณมีทางออกที่ดีกว่าสำหรับสิ่งนั้นหรือ BTW ตรวจสอบstackoverflow.com/questions/36354325/…
Dalibor

186

ใน ES6 คุณสามารถทำได้:

Array(N).fill().map((e,i)=>i+1);

http://jsbin.com/molabiluwa/edit?js,console

แก้ไข: เปลี่ยนArray(45)เป็นArray(N)เนื่องจากคุณได้อัปเดตคำถามแล้ว

console.log(
  Array(45).fill(0).map((e,i)=>i+1)
);


3
+1 เพราะมันเป็นโอใหญ่กว่า.join.splitรุ่นที่น่ารังเกียจ- แต่ฉันก็ยังคิดว่าลูปต่ำต้อยดีกว่า
Robin

ฉันเห็นด้วย @Robin - ความซับซ้อนของอัลกอริธึมกันลูปอันต่ำต้อยสามารถอ่านได้มากขึ้นเสมอ อย่างไรก็ตามด้วยการถือกำเนิดของ lambdas ใน Java ฉันคิดว่าmapอีกไม่นานจะกลายเป็นมาตรฐานสำหรับสิ่งต่าง ๆ เช่นนี้
เนท

4
const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]
Robin

8
ฉันไม่เข้าใจว่าทำไม.fill()มีความจำเป็น ฉันเห็นว่ามันเป็นเมื่อฉันทดสอบกับการจำลองของโหนด แต่เนื่องจากArray(1)[0] === undefinedการเรียกเพื่อเติม () มีความแตกต่างกันArray(1).fill(undefined)อย่างไร
โดมินิ

11
สำหรับคนอื่นที่มีความสนใจความแตกต่างระหว่าง Array (N) และ Array (N) .fill () นั้นได้รับการอธิบายที่นี่
Dominic

108

ใช้วิธี Underscore _.range ที่นิยมมาก

// _.range([start], stop, [step])

_.range(10); // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_.range(1, 11); // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
_.range(0, 30, 5); // => [0, 5, 10, 15, 20, 25]
_.range(0, -10, -1); //  => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
_.range(0); // => []


น่ากลัว แสดงโครงการขนาดใหญ่ที่ไม่ใช้ขีดเส้นใต้ ...
Erez Cohen

63
function range(start, end) {
    var foo = [];
    for (var i = start; i <= end; i++) {
        foo.push(i);
    }
    return foo;
}

จากนั้นโทรมาโดย

var foo = range(1, 5);

ไม่มีวิธีการทำเช่นนี้ใน Javascript แต่เป็นฟังก์ชันยูทิลิตี้ที่ถูกต้องสมบูรณ์ในการสร้างหากคุณต้องการทำมากกว่าหนึ่งครั้ง

แก้ไข: ในความคิดของฉันต่อไปนี้เป็นฟังก์ชั่นช่วงที่ดีกว่า อาจเป็นเพราะฉันลำเอียงโดย LINQ แต่ฉันคิดว่ามันมีประโยชน์มากกว่าในหลายกรณี ไมล์สะสมของคุณอาจแตกต่างกันไป

function range(start, count) {
    if(arguments.length == 1) {
        count = start;
        start = 0;
    }

    var foo = [];
    for (var i = 0; i < count; i++) {
        foo.push(start + i);
    }
    return foo;
}

2
ฉันชอบสิ่งนี้. หากคุณต้องการใช้ไมล์พิเศษด้วยคุณสามารถประกาศเป็น Array.prototype.range = function (เริ่มต้นสิ้นสุด) {... }; จากนั้นคุณสามารถเรียกช่วง (x, y) บนวัตถุ Array ใด ๆ
Zach Rattner

8
ค่อนข้างทำให้มันเป็นวิธีการArrayแทนArray.prototypeเพราะไม่มีเหตุผล (มันอาจจะถือว่าค่อนข้างโง่) ที่จะมีวิธีนี้ในทุก ๆ อาร์เรย์
ปฏิบัติหน้าที่

9
Array.range(1, 5)อาจจะมีความเหมาะสมมากขึ้น [].range(1, 5)แต่มีบางสิ่งบางชนิดของเย็นเกี่ยวกับการเขียน
MooGoo

"แทนที่จะทำให้เป็นวิธีของ Array แทนที่จะเป็น Array.prototype" - อะไรคือความแตกต่าง? คุณหมายถึงเฉพาะอาเรย์เท่านั้น?
pilau

3
@pilau เช่นเดียวกับ adamse พูดว่ามันดูแปลก ถ้ามันอยู่บนต้นแบบคุณสามารถพูดfoo = [1, 2, 3]; bar = foo.range(0, 10);ได้ แต่นั่นเป็นเพียง ... สับสน bar = Array.range(0, 10)มีความชัดเจนและชัดเจนมากขึ้น ช่วงไม่มีอะไรเกี่ยวข้องกับอินสแตนซ์ดังนั้นจึงไม่มีเหตุผลที่จะทำให้เป็นวิธีการแบบอินสแตนซ์
เอียนเฮนรี่

53

วิธีที่เร็วที่สุดในการกรอกข้อมูลArrayใน v8 คือ:

[...Array(5)].map((_,i) => i);

ผลลัพธ์จะเป็น: [0, 1, 2, 3, 4]


มีวิธีทำโดยไม่มีตัวแปรพิเศษ _
bluejayke

@bluejayke ไม่มี :(
аlexdykyі

รุนแรงคุณรู้ไหมว่าซอร์สโค้ดของ. map คืออะไร? ฉันไม่แน่ใจว่ามันเร็วกว่าลูปหรือไม่ แต่ถ้าไม่จริงแล้วเราสามารถกำหนดคุณสมบัติและสร้างใหม่ได้
bluejayke

49

คำถามนี้มีคำตอบที่ซับซ้อนมากมาย แต่เป็นแบบง่าย ๆ :

[...Array(255).keys()].map(x => x + 1)

นอกจากนี้แม้ว่าข้างต้นจะสั้น (และเรียบร้อย) ในการเขียนฉันคิดว่าต่อไปนี้จะเร็วขึ้นเล็กน้อย (สำหรับความยาวสูงสุด:

127, Int8,

255, Uint8,

32,767, Int16,

65,535, Uint16,

2,147,483,647, Int32,

4,294,967,295, Uint32

(ขึ้นอยู่กับค่าจำนวนเต็มสูงสุด ) และยังมีเพิ่มเติมในอาร์เรย์ที่พิมพ์ด้วย ):

(new Uint8Array(255)).map(($,i) => i + 1);

แม้ว่าวิธีนี้จะไม่เหมาะอย่างยิ่งเพราะมันสร้างสองอาร์เรย์และใช้การประกาศตัวแปรพิเศษ "$" (ไม่แน่ใจว่าจะหลีกเลี่ยงวิธีใดในการใช้วิธีนี้) ฉันคิดว่าวิธีแก้ปัญหาต่อไปนี้เป็นวิธีที่เร็วที่สุดที่จะทำได้:

for(var i = 0, arr = new Uint8Array(255); i < arr.length; i++) arr[i] = i + 1;

คุณสามารถใช้ตัวแปร "arr" ในขอบเขตปัจจุบันได้โดยง่าย

หากคุณต้องการสร้างฟังก์ชั่นที่เรียบง่ายจากฟังก์ชั่นนี้ (ด้วยการยืนยันขั้นพื้นฐาน):

function range(min, max) {
    min = min && min.constructor == Number ? min : 0;
    !(max && max.constructor == Number && max > min) && // boolean statements can also be used with void return types, like a one-line if statement.
        ((max = min) & (min = 0));  //if there is a "max" argument specified, then first check if its a number and if its graeter than min: if so, stay the same; if not, then consider it as if there is no "max" in the first place, and "max" becomes "min" (and min becomes 0 by default)

    for(var i = 0, arr = new (
        max < 128 ? Int8Array : 
        max < 256 ? Uint8Array :
        max < 32768 ? Int16Array : 
        max < 65536 ? Uint16Array :
        max < 2147483648 ? Int32Array :
        max < 4294967296 ? Uint32Array : 
        Array
    )(max - min); i < arr.length; i++) arr[i] = i + min;
    return arr;
}



//and you can loop through it easily using array methods if you want
range(1,11).forEach(x => console.log(x));

//or if you're used to pythons `for...in` you can do a similar thing with `for...of` if you want the individual values:
for(i of range(2020,2025)) console.log(i);

//or if you really want to use `for..in`, you can, but then you will only be accessing the keys:

for(k in range(25,30)) console.log(k);

console.log(
    range(1,128).constructor.name,
    range(200).constructor.name,
    range(400,900).constructor.name,
    range(33333).constructor.name,
    range(823, 100000).constructor.name,
    range(10,4) // when the "min" argument is greater than the "max", then it just considers it as if there is no "max", and the new max becomes "min", and "min" becomes 0, as if "max" was never even written
);


ดังนั้นด้วยฟังก์ชั่นดังกล่าวข้างต้นช้าสุด "ง่ายหนึ่งซับ" กลายเป็นซุปเปอร์เร็วแม้สั้น:

range(1,14000);

@JVG แต่ไม่ใช่สำหรับฟังก์ชั่นที่เร็วขึ้น?
bluejayke

ถูกต้อง มันเป็นเรื่องง่ายที่ทุกคนมองหา!
supersan

@supersan ถึงแม้ว่ามันจะช้าสุด ๆ :)
bluejayke

จาวาสคริปต์ที่ทันสมัยด้วยfillวิธีการใหม่:Array(255).fill(0,0,255)
cacoder

@cacoder มันเร็วแค่ไหนมันมีอาร์เรย์กี่ตัวและมีการทำซ้ำอีกกี่ครั้ง?
bluejayke

42

คุณสามารถใช้สิ่งนี้:

new Array(/*any number which you want*/)
    .join().split(',')
    .map(function(item, index){ return ++index;})

ตัวอย่างเช่น

new Array(10)
    .join().split(',')
    .map(function(item, index){ return ++index;})

จะสร้างอาร์เรย์ต่อไปนี้:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

นอกจากนี้ทำไมไม่new Array(10).join().split(',').map(function() {return ++arguments[1]});?
super

1
@Murplyx สำหรับบางกรณีฟังก์ชั่นที่มีข้อโต้แย้งภายในจะไม่ได้รับการปรับให้เหมาะสมโดยเครื่องยนต์ JS (จริงแม้กระทั่งสำหรับ V8 ดูjsperf.com/arguments-vs-array-argument/2 )
nktssh

4
นี่เป็นวิธีแก้ปัญหาที่น่าสนใจ แต่จริง ๆ แล้วเป็นไปไม่ได้เลย - การแยกอาเรย์3 ครั้ง (หนึ่งครั้งjoin, ครั้งต่อไปsplit, และอีกครั้งสำหรับสิ่งที่คุณต้องการทำจริง ๆ ) ไม่ดีเลย - ฉันรู้ว่าพวกเขาดูเหมือนจะตกหล่น ด้วยเหตุผลบางอย่าง แต่มันจะดีกว่าถ้าจะใช้วงแบบเก่าที่ดี!
Robin

42

ES6 นี้จะทำเคล็ดลับ:

[...Array(12).keys()]

ตรวจสอบผล:

[...Array(12).keys()].map(number => console.log(number))


5
จริงๆแล้วพวกเขาถามหา 1..N ไม่ใช่ 0..N-1
YakovL

1
ใช่[...Array(N + 1).keys()].slice(1)จะให้ผล 1..N
David G

ด้วยเหตุผลบางอย่างโซลูชันนี้ไม่สามารถใช้งานได้ในเวอร์ชันการผลิตจากแอป Expo (ตอบสนองตามพื้นเมือง) [...Array(N + 1).keys()]รหัสนี้ส่งกลับอาร์เรย์ที่ว่างเปล่า แต่เพียงในโหมดการผลิตโดยใช้งานโหมดการพัฒนา
FabianoLothor

3
.keys()คำตอบที่ได้รับแล้วปีที่ผ่านมาและมี 500 + upvotes คำตอบของคุณเพิ่มไปยังอะไร?
Dan Dascalescu

39

หากคุณบังเอิญใช้d3.jsในแอปของคุณอย่างที่ฉันเป็น D3 จะมีฟังก์ชั่นช่วยเหลือที่ใช้สำหรับคุณ

ดังนั้นในการรับอาร์เรย์จาก 0 ถึง 4 มันง่ายเหมือน:

d3.range(5)
[0, 1, 2, 3, 4]

และรับอาร์เรย์ตั้งแต่ 1 ถึง 5 ตามที่คุณร้องขอ:

d3.range(1, 5+1)
[1, 2, 3, 4, 5]

ลองดูบทช่วยสอนนี้สำหรับข้อมูลเพิ่มเติม


ความคิดเห็นนี้ทำให้ฉันมีความคิดในการค้นหาฟังก์ชั่น range ()ใน RamdaJS ซึ่งเกิดขึ้นเป็นห้องสมุด JS ที่ฉันทำงานกับโครงการปัจจุบันของฉัน สมบูรณ์
สัณฐาน


38

นี่อาจเป็นวิธีที่เร็วที่สุดในการสร้างอาร์เรย์ของตัวเลข

ที่สั้นที่สุด

var a=[],b=N;while(b--)a[b]=b+1;

inline

var arr=(function(a,b){while(a--)b[a]=a;return b})(10,[]);
//arr=[0,1,2,3,4,5,6,7,8,9]

หากคุณต้องการเริ่มต้นจาก 1

var arr=(function(a,b){while(a--)b[a]=a+1;return b})(10,[]);
//arr=[1,2,3,4,5,6,7,8,9,10]

ต้องการฟังก์ชั่นหรือไม่?

function range(a,b,c){c=[];while(a--)c[a]=a+b;return c}; //length,start,placeholder
var arr=range(10,5);
//arr=[5,6,7,8,9,10,11,12,13,14]

ทำไม?

  1. while เป็นวงที่เร็วที่สุด

  2. การตั้งค่าโดยตรงเร็วกว่า push

  3. [] เร็วกว่า new Array(10)

  4. มันสั้น ... ดูรหัสแรก จากนั้นดูฟังก์ชั่นอื่น ๆ ทั้งหมดที่นี่

หากคุณต้องการไม่สามารถมีชีวิตอยู่ได้โดยไม่ต้องสำหรับ

for(var a=[],b=7;b>0;a[--b]=b+1); //a=[1,2,3,4,5,6,7]

หรือ

for(var a=[],b=7;b--;a[b]=b+1); //a=[1,2,3,4,5,6,7]

8
จะเป็นการดีกว่าหากคุณสำรองข้อมูลการเรียกร้องเหล่านี้ด้วยการวัดประสิทธิภาพ ลองjsperf.com
แมตต์บอล

2
ls jsperf ... กรุณา Matt เพียงเพราะคุณไม่ชอบคำตอบของฉันหยุด downvoting คนอื่น ๆ ของฉัน ... stackoverflow.com/a/18344296/2450730 ... ใช้ console.time () หรือวิธีที่เรียกว่า ... ไม่ใช่ jsperf .
cocco

4
FYI: ตามที่ John Reisig เผยแพร่ครั้งแรกเมื่อไม่กี่ปีที่ผ่านมา - ในบางแพลตฟอร์ม (หมายถึง windows: P) เวลาจะถูกป้อนเข้าสู่เบราว์เซอร์ทุกๆ 16ms นอกจากนี้ยังมีปัญหาอื่น ๆ เกี่ยวกับการวัดเวลาของการดำเนินการในสภาพแวดล้อมมัลติทาสกิ้ง jsperf.com ได้ดำเนินการทดสอบเพื่อให้ถูกต้องทางสถิติ มันตกลงที่จะทำงานconsole.time()ที่จะได้รับสัญชาติญาณ แต่สำหรับหลักฐานที่คุณจะต้อง jsperf.com และมันแสดงให้เห็นคุณข้ามเบราว์เซอร์ผลจากคนอื่น ๆ (ฮาร์ดแวร์ที่แตกต่างกัน ฯลฯ )
naugtur

3
@cocco นี้ไม่ถูกต้อง:var a=[],b=N;while(b--){a[b]=a+1};
vintagexav

5
@ cocco- ในขณะที่ไม่ได้เสมอเร็วกว่าลูปอื่น ๆ ในบางเบราว์เซอร์การลดลงในขณะที่ลูปนั้นช้ากว่าลูปสำหรับลูปมากคุณไม่สามารถสร้างคำสั่งทั่วไปเกี่ยวกับประสิทธิภาพของจาวาสคริปต์เช่นนั้นได้เนื่องจากมีการใช้งานจำนวนมาก อย่างไรก็ตามโดยทั่วไปฉันชอบแนวทางของคุณ ;-)
RobG

32

วิธีใหม่ในการเติมArrayคือ:

const array = [...Array(5).keys()]
console.log(array)

ผลลัพธ์จะเป็น: [0, 1, 2, 3, 4]


นี่เป็นคำตอบที่ดีจริงๆแม้ว่าคำถามจะมาจาก 1-N ไม่ใช่ 0- (N-1)
bluejayke

31

หากคุณใช้ lodash คุณสามารถใช้_.range :

_.range([start=0], end, [step=1])

สร้างอาร์เรย์ของตัวเลข (บวกและ / หรือลบ) ที่กำลังดำเนินการตั้งแต่เริ่มต้นจนถึง แต่ไม่รวมถึงสิ้นสุด ขั้นตอนที่ -1 จะถูกใช้หากระบุการเริ่มต้นเชิงลบโดยไม่มีการสิ้นสุดหรือขั้นตอน หากไม่ได้ระบุจุดสิ้นสุดจะตั้งค่าให้เริ่มต้นด้วยเริ่มจากนั้นตั้งค่าเป็น 0

ตัวอย่าง:

_.range(4);
// ➜ [0, 1, 2, 3]

_.range(-4);
// ➜ [0, -1, -2, -3]

_.range(1, 5);
// ➜ [1, 2, 3, 4]

_.range(0, 20, 5);
// ➜ [0, 5, 10, 15]

_.range(0, -4, -1);
// ➜ [0, -1, -2, -3]

_.range(1, 4, 0);
// ➜ [1, 1, 1]

_.range(0);
// ➜ []

30

ด้วย ES6 คุณสามารถทำได้:

// `n` is the size you want to initialize your array
// `null` is what the array will be filled with (can be any other value)
Array(n).fill(null)

เนื่องจากค่าของอาเรย์นั้นเต็มไปด้วยการใช้โซลูชั่นนี้mapและforEachจะใช้งานได้
dontmentionthebackup

27

รายงานสรุปขั้นสุดท้าย .. Drrruummm Rolll -

นี่คือรหัสที่สั้นที่สุดในการสร้างอาร์เรย์ขนาด N (ที่นี่ 10) โดยไม่ต้องใช้ ES6 เวอร์ชันของCoccoด้านบนนั้นปิด แต่ไม่สั้นที่สุด

(function(n){for(a=[];n--;a[n]=n+1);return a})(10)

แต่ชนะไม่มีปัญหานี้กอล์ฟรหัส (การแข่งขันในการแก้ปัญหาที่เกิดขึ้นโดยเฉพาะอย่างยิ่งในไบต์น้อยที่สุดของ source code) คือนิโก้ Ruotsalainen ใช้อาร์เรย์สร้างและผู้ประกอบการ ES6 การแพร่กระจาย (ไวยากรณ์ส่วนใหญ่ของ ES6 เป็น typeScript ที่ถูกต้อง แต่การติดตามไม่ได้ดังนั้นควรพิจารณาในขณะที่ใช้)

[...Array(10).keys()]

ทำไมต้องลงคะแนน รายการคำตอบยาว ๆ ยากที่จะติดตามดังนั้นให้คิดถึงการสรุป
sapy

ไม่ใช่หรือ [... อาร์เรย์ (10) .keys ()]
เกร็ก

Webstorm แนะนำ (Array ใหม่ (10)). keys () ถูกต้องไหม?
Guy

(Array ใหม่ (10)). keys (), ส่งคืน ArrayIterator {} ไม่ใช่ Array
sapy

aนี้จะสร้างตัวแปรทั่วโลก การวนซ้ำควรเป็นfor(var a=[];n--;a[n]=n+1)
kube

20

มีอีกวิธีหนึ่งใน ES6 โดยใช้Array.fromซึ่งใช้เวลา 2 ข้อโต้แย้งข้อแรกคือ arrayLike (ในกรณีนี้คืออ็อบเจกต์ที่มีlengthคุณสมบัติ) และอันที่สองคือฟังก์ชั่นการแมป (ในกรณีนี้เราจับคู่รายการกับดัชนี)

Array.from({length:10}, (v,i) => i)

นี่คือสั้นและสามารถใช้สำหรับลำดับอื่น ๆ เช่นสร้างเลขคู่

Array.from({length:10}, (v,i) => i*2)

นอกจากนี้ยังมีประสิทธิภาพที่ดีกว่าวิธีอื่น ๆ ส่วนใหญ่เพราะมันวนซ้ำเพียงครั้งเดียวผ่านอาร์เรย์ ตรวจสอบ snippit เพื่อเปรียบเทียบ

// open the dev console to see results

count = 100000

console.time("from object")
for (let i = 0; i<count; i++) {
  range = Array.from({length:10}, (v,i) => i )
}
console.timeEnd("from object")

console.time("from keys")
for (let i =0; i<count; i++) {
  range = Array.from(Array(10).keys())
}
console.timeEnd("from keys")

console.time("apply")
for (let i = 0; i<count; i++) {
  range = Array.apply(null, { length: 10 }).map(function(element, index) { return index; })
}
console.timeEnd("apply")


เฮ้เรียบร้อยฉันชอบมันมาก อย่างไรก็ตามมันไม่ได้แสดงผลลัพธ์ที่คาดหวัง OP หากต้องการทำเช่นนั้นจะต้องมีการเขียนเป็นArray.from({length:N}, (v,i) => i+1)
CervEd

เหล่าแฮ็ก Neato ยังคง5-10x ช้าดีกว่าเก่าสำหรับวง
Dan Dascalescu

16

การใช้วิธี Array ใหม่และ=>ฟังก์ชั่นไวยากรณ์จากมาตรฐาน ES6 (เฉพาะ Firefox ในขณะที่เขียน)

โดยการเติมหลุมด้วยundefined:

Array(N).fill().map((_, i) => i + 1);

Array.fromเปลี่ยน "หลุม" undefinedให้Array.mapทำงานตามที่คาดไว้:

Array.from(Array(5)).map((_, i) => i + 1)

7
ในทำนองเดียวกันคุณยังสามารถทำต่อไปนี้ใน ES6 Array.from({length: N}, (v, k) => k)นี้:
XåpplI'-I0llwlg'I -

วิธีการของ Xappli เป็นที่ต้องการ: Array.from ถูกสร้างขึ้นสำหรับสถานการณ์ที่แน่นอนนี้เกือบทั้งหมดและมันหมายถึงการเรียกกลับการแมป มันเป็นทางออกที่ดีปัญหาทั่วไปของที่ต้องการวิธีการใช้อาร์เรย์ในสิ่งอาร์เรย์เหมือนโดยไม่ต้อง resorting ละเอียดวิธีการเหมือนArray.prototype.map.callเช่นการ NodeLists document.querySelectorAllกลับมาจาก developer.mozilla.org/en/docs/Web/JavaScript/Reference/
......

ฉันกำลังชั่งน้ำหนักนี้เทียบกับช่วงขีดล่างของไวยากรณ์และช่วงอ่านดีกว่า
ooolala

ในทางเทคนิคแล้วมันไม่Array.fromเปลี่ยนค่าเบาบางลง แต่Array(5)จะเรียกว่าเป็นวัตถุข้อโต้แย้งซึ่งในทางกลับตีความค่าเบาบางเป็นค่าที่ไม่ได้กำหนด :)
CervEd

15

Array(...Array(9)).map((_, i) => i);

console.log(Array(...Array(9)).map((_, i) => i))


ดี! นอกจากนี้ยังสามารถเขียนเรื่องนี้ให้กระชับยิ่งขึ้นได้อีกด้วย[...Array(9)].map((_, i) => i)
Eamonn O'Brien-Strain



10

อีกเพียงรุ่นES6

ด้วยการใช้Array.fromอาร์กิวเมนต์ตัวเลือกที่สอง:

Array.from (arrayLike [, mapFn [, thisArg]])

เราสามารถสร้างอาเรย์ที่มีหมายเลขจากArray(10)ตำแหน่งว่าง:

Array.from(Array(10), (_, i) => i)

var arr = Array.from(Array(10), (_, i) => i);
document.write(arr);


นี่คือความซับซ้อนมากขึ้นและ ~ 10 [...Array(11).keys()].slice(1)เท่าช้ากว่า
Dan Dascalescu

10

ดูเหมือนว่ามีเพียงรสชาติเดียวที่ไม่ได้อยู่ในรายการคำตอบที่ค่อนข้างสมบูรณ์นี้คือหนึ่งในนั้นมีเครื่องกำเนิดไฟฟ้า เพื่อแก้ไขว่า:

const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]

ซึ่งสามารถใช้ดังนี้:

gen(4) // [0,1,2,3]

สิ่งที่ดีเกี่ยวกับเรื่องนี้คือคุณไม่เพียง แต่ต้องเพิ่ม ... เพื่อรับแรงบันดาลใจจากคำตอบที่ @ igor-shubin คุณสามารถสร้างอาร์เรย์ของ randoms ได้อย่างง่ายดายมาก:

const gen = N => [...(function*(){let i=0;
  while(i++<N) yield Math.random()
})()]

และมากกว่าสิ่งที่มีราคาแพงในเชิงปฏิบัติเช่น:

const slow = N => new Array(N).join().split(',').map((e,i)=>i*5)
// [0,5,10,15,...]

คุณสามารถทำได้แทน:

const fast = N => [...(function*(){let i=0;while(i++<N)yield i*5})()]

10

คุณสามารถใช้การเติม Array และแผนที่ได้จาก Es6 เช่นเดียวกับบางคนที่แนะนำในคำตอบที่ให้ไว้สำหรับคำถามนี้ ด้านล่างเป็นตัวอย่างบางส่วน:

Example-One: Array(10).fill(0).map((e,i)=>i+1)

Result-One: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Example-Two: Array(100/10).fill(0).map((e,i)=>(i*10)+10)

Result-Two:[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

ฉันชอบสิ่งนี้เพราะฉันพบว่ามันตรงไปตรงมาและง่ายขึ้น



9

ใช้ ES6

const generateArray = n => [...Array(n)].map((_, index) => index + 1);

ขอบคุณ! นี่เป็นคำตอบที่หรูหราที่สุดในความคิดของฉัน! หนึ่งสามารถใช้Array.from(Array(n))หากผู้ประกอบการแพร่กระจายไม่ได้รับการสนับสนุน
Amit

ตอนแรกฉันไม่รู้ว่าทำไมคุณต้องใช้โอเปอเรเตอร์สเปรด แต่จากนั้นฉันอ่านต่อไปนี้เกี่ยวmapกับ MDN : "มันไม่ได้ถูกเรียกสำหรับองค์ประกอบที่หายไปของอาเรย์ (นั่นคือดัชนีที่ไม่เคยถูกตั้งค่าซึ่งมี ถูกลบไปแล้วหรือยังไม่เคยกำหนดค่า)
battmanz

9

Object.keys(Array.apply(0, Array(3))).map(Number)

[0, 1, 2]ผลตอบแทน คล้ายกับคำตอบที่ยอดเยี่ยมของ Igor Shubinแต่มีเล่ห์เหลี่ยมน้อยกว่าเล็กน้อย

คำอธิบาย:

  • Array(3) // [undefined × 3]สร้างอาร์เรย์ที่มีความยาว n = 3 น่าเสียดายที่อาเรย์นี้แทบจะไร้ประโยชน์กับเราดังนั้นเราต้อง ...
  • Array.apply(0,Array(3)) // [undefined, undefined, undefined]ทำให้อาร์เรย์ iterable หมายเหตุ: เป็นโมฆะทั่วไปของอาร์กิวเมนต์แรกที่ใช้ แต่สั้นกว่า 0
  • Object.keys(Array.apply(0,Array(3))) // ['0', '1', '2'] จากนั้นรับค่าคีย์ของอาเรย์ (ใช้งานได้เนื่องจากอาเรย์คืออาร์เรย์ของ typeof เป็นวัตถุที่มีดัชนีสำหรับคีย์
  • Object.keys(Array.apply(0,Array(3))).map(Number) // [0, 1, 2] และแมปกุญแจ, แปลงสตริงเป็นตัวเลข
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.