Cách tạo mảng chứa 1 lệch N


1163

Tôi đang tìm kiếm bất kỳ giải pháp thay thế nào dưới đây để tạo một mảng JavaScript chứa từ 1 đến N trong đó N chỉ được biết khi chạy.

var foo = [];

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

Đối với tôi cảm giác như có một cách để làm điều này mà không cần vòng lặp.


224
Sau khi đọc toàn bộ trang này, tôi đã đi đến kết luận rằng vòng lặp đơn giản của riêng bạn là đơn giản nhất, dễ đọc nhất và ít bị lỗi nhất.
Kokodoko

Nếu bất cứ ai cần một cái gì đó cao cấp hơn, tôi đã tạo một lib node.js thực hiện điều này cho các số, chữ cái, phạm vi âm / dương, v.v. github.com/jonschlinkert/fill-range . Nó được sử dụng trong github.com/jonschlinkert/braces để mở rộng
niềng răng

1
Bạn nên chỉnh sửa để nói "Cách tạo một mảng có độ dài N" thay vì "... chứa 1 ... N", phần sau ngụ ý sẽ có các phần tử có giá trị từ 1 đến N
Steven Landow

7
@StevenLandow tại sao OP nên đổi tên? Anh ta muốn một mảng với các giá trị 1 ... N?
Andre Elrico

Câu hỏi hay, tiêu đề tốt, (kinda) câu trả lời ngớ ngẩn.
Bitterblue

Câu trả lời:


381

Nếu tôi có được những gì bạn đang theo đuổi, bạn muốn một dãy số 1..nmà sau này bạn có thể lặp lại.

Nếu đây là tất cả những gì bạn cần, bạn có thể làm điều này thay thế?

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

sau đó khi bạn muốn sử dụng nó ... (chẳng hạn như không được tối ưu hóa)

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

ví dụ: nếu bạn không cần lưu trữ bất cứ thứ gì trong mảng, bạn chỉ cần một thùng chứa có độ dài phù hợp mà bạn có thể lặp lại ... điều này có thể dễ dàng hơn.

Xem nó trong hành động ở đây: http://jsfiddle.net/3kcvm/


4
ấn tượng bạn quản lý để diễn đạt câu hỏi của tôi tốt hơn tôi có thể, bạn thực sự đúng như phản ánh tất cả những gì tôi cần là một dãy số mà sau này tôi có thể lặp lại :) Cảm ơn câu trả lời của bạn.
Godder

147
@Godder: Nếu đây là những gì bạn đang tìm kiếm, tại sao bạn cần một mảng? Một đơn giản var n = 45;và sau đó lặp từ 1..nsẽ làm.
casifer

3
@Godder - Để lưu ý, nếu bạn muốn giảm kích thước của mảng sau khi nó được tạo theo chiều dài M, chỉ cần sử dụng foo.length = M--- Thông tin cắt bỏ bị mất. Xem nó trong hành động ==> jsfiddle.net/ACMXp
Peter Ajtai

24
Tôi thực sự không hiểu tại sao câu trả lời này thậm chí còn có sự ủng hộ ... đặc biệt là khi chính OP đồng ý rằng nó không có ý nghĩa gì trong một vài bình luận ở trên vì anh ta có thể làm được var n = 45;.
plalx

72
@scunliffe: Xin lưu ý, điều new Array(45);đó không "tạo ra một mảng phần tử 45" (có nghĩa tương tự như [undefined,undefined,..undefined]vậy). Nó khá "tạo mảng trống với length = 45" ( [undefined x 45]), giống như var foo = []; foo.length=45;. Đó là lý do forEachmapsẽ không áp dụng trong trường hợp này.
tomalec

1309

Trong ES6 sử dụng các phương thức Array from ()key () .

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

Phiên bản ngắn hơn sử dụng toán tử trải .

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

75
Chỉ cần một lưu ý, điều này sẽ luôn bắt đầu từ 0. Sẽ cần xâu chuỗi a mapvào mảng để điều chỉnh các giá trị ( [...Array(10).keys()].map(x => x++);) để bắt đầu lúc 1
Sterling Archer

32
Chỉ cần thay đổi map(x => x++)thành map(x => ++x)do sự gia tăng quyền ưu tiên xảy ra sau khi trả về giá trị :)
Brock

93
Ơ cái gì!? Tại sao mapkhi bạn có thể đơn giản slice? [...Array(N+1).keys()].slice(1)
Robin

19
Hoặc không sử dụng keysvà chỉ có 1 bản đồ ->Array.from(Array(10)).map((e,i)=>i+1)
yonatanmn

60
Hoặc không sử dụng khóa và bản đồ và chỉ chuyển một chức năng ánh xạ tớifrom Array.from(Array(10), (e,i)=>i+1)
Fabio Antunes

844

Bạn có thể làm như vậy:

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

kết quả: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

hoặc với các giá trị ngẫu nhiên:

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

kết quả: [0.7082694901619107, 0.9572225909214467, 0.8586748542729765, 0.8653848143294454, 0,00839877473190427, 0.9911756622605026, 0.8133423360995948, 0.8377588757575

Giải trình

Đầu tiên, lưu ý rằng Number.call(undefined, N)tương đương với Number(N), mà chỉ trả về N. Chúng ta sẽ sử dụng thực tế đó sau.

Array.apply(null, [undefined, undefined, undefined])tương đương với Array(undefined, undefined, undefined), nó tạo ra một mảng ba phần tử và gán undefinedcho từng phần tử.

Làm thế nào bạn có thể khái quát điều đó cho N yếu tố? Xem xét cách thức Array()hoạt động, đi như thế này:

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;
}

Kể từ ECMAScript 5 , Function.prototype.apply(thisArg, argsArray)cũng chấp nhận một đối tượng giống như mảng gõ vịt làm tham số thứ hai của nó. Nếu chúng ta gọi Array.apply(null, { length: N }), nó sẽ thực thi

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

Bây giờ chúng ta có một mảng N -element, với mỗi phần tử được đặt thành undefined. Khi chúng ta gọi .map(callback, thisArg)nó, mỗi phần tử sẽ được đặt thành kết quả của callback.call(thisArg, element, index, array). Do đó, [undefined, undefined, …, undefined].map(Number.call, Number)sẽ ánh xạ từng phần tử tới (Number.call).call(Number, undefined, index, array), giống như Number.call(undefined, index, array), như chúng ta đã quan sát trước đó, đánh giá index. Điều đó hoàn thành mảng có các phần tử giống như chỉ mục của chúng.

Tại sao phải trải qua những rắc rối Array.apply(null, {length: N})thay vì chỉ Array(N)? Rốt cuộc, cả hai biểu thức sẽ dẫn đến một mảng N -element của các phần tử không xác định. Sự khác biệt là trong biểu thức trước, mỗi phần tử được đặt rõ ràng thành không xác định, trong khi ở phần sau, mỗi phần tử không bao giờ được đặt. Theo tài liệu của .map():

callbackchỉ được gọi cho các chỉ mục của mảng có các giá trị được gán; nó không được gọi cho các chỉ mục đã bị xóa hoặc chưa bao giờ được gán giá trị.

Do đó, Array(N)là không đủ; Array(N).map(Number.call, Number)sẽ cho kết quả trong một mảng chưa được khởi tạo có độ dài N .

Khả năng tương thích

Vì kỹ thuật này dựa trên hành vi Function.prototype.apply()được chỉ định trong ECMAScript 5, nên nó sẽ không hoạt động trong các trình duyệt tiền ECMAScript 5 như Chrome 14 và Internet Explorer 9.


62
+1 cho sự thông minh nhưng xin lưu ý đây là đơn đặt hàng có cường độ lớn hơn so với vòng lặp nguyên thủy: jsperf.com/array-magic-vs-for
warpech

7
Rất thông minh - có lẽ là quá. Khai thác thực tế rằng thông số Function.prototype.callđầu tiên của thisđối tượng là đối tượng để ánh xạ trực tiếp qua Array.prototype.maptham số iterator có độ sáng nhất định với nó.

14
Điều này thực sự, thực sự thông minh (biên giới về việc lạm dụng JS). Cái nhìn sâu sắc thực sự quan trọng ở đây là sự bình dị mapvề các giá trị chưa được gán, theo ý kiến ​​của tôi. Một phiên bản khác (và có thể rõ ràng hơn một chút, mặc dù dài hơn) là: Array.apply(null, { length: N }).map(function(element, index) { return index; })
Ben Reich

6
@BenReich Thậm chí tốt hơn (về mức độ lạm dụng JS): Array.apply(null, new Array(N)).map(function(_,i) { return i; }) hoặc, trong trường hợp chức năng es6 và mũi tên, thậm chí còn ngắn hơn: Array.apply(null, new Array(N)).map((_,i) => i)
oddy

1
NẾU điều này trả về một mảng bắt đầu từ 1, nó thực sự sẽ trả lời câu hỏi của OP
Sarsaparilla

483

Nhiều cách sử dụng ES6

Sử dụng toán tử lây lan ( ...) và phương thức khóa

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

Điền / Bản đồ

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

Array.from

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

Array.from và { length: N }hack

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

Lưu ý về hình thức tổng quát

Tất cả các hình thức trên mảng có thể sản xuất được khởi tạo với giá trị khá nhiều bất kỳ mong muốn bằng cách thay đổi i+1để biểu hiện yêu cầu (ví dụ như i*2, -i, 1+i*2, i%2và vv). Nếu biểu thức có thể được biểu thị bởi một số chức năng fthì biểu mẫu đầu tiên trở nên đơn giản

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

Ví dụ:

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

Vì mảng được khởi tạo với undefinedtrên mỗi vị trí, giá trị của v sẽ làundefined

Ví dụ hiển thị tất cả các hình thức

Ví dụ chung hơn với chức năng khởi tạo tùy chỉnh ftức là

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

hoặc thậm chí đơn giản hơn

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


33
Câu trả lời hay nhất IMHO. Xem thêm developer.mozilla.org/de/docs/Web/JavaScript/Reference/
Kẻ

5
Sử dụng k ++ cho các mảng bắt đầu từ 0
Borgboy 15/03/2017

1
Nếu bạn muốn tăng, không sử dụng k++, sử dụng ++k.
Alex

4
Hãy coi chừng Array.from không được hỗ trợ trong IE, trừ khi bạn đang điền vào nó.
Lauren

2
Để làm cho trình biên dịch TS hài lòng, hãy xem xét việc thay thế param không sử dụng bằng lodash: Array.from ({length: 5}, (_, k) => k + 1);
Hành trình

297

Mảng quản lý bẩm sinh chiều dài của họ. Khi chúng đi qua, các chỉ mục của chúng có thể được giữ trong bộ nhớ và được tham chiếu tại thời điểm đó. Nếu một chỉ số ngẫu nhiên cần được biết, indexOfphương pháp có thể được sử dụng.


Điều này cho biết, đối với nhu cầu của bạn, bạn có thể chỉ muốn khai báo một mảng có kích thước nhất định:

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

Lây lan

Sử dụng toán tử trải rộng ( ...) và keysphương thức, cho phép bạn tạo một mảng tạm thời có kích thước N để tạo các chỉ mục và sau đó một mảng mới có thể được gán cho biến của bạn:

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

Điền / Bản đồ

Trước tiên, bạn có thể tạo kích thước của mảng bạn cần, điền vào đó không xác định và sau đó tạo một mảng mới bằng cách sử dụng map, đặt từng phần tử cho chỉ mục.

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

Array.from

Điều này sẽ được khởi tạo theo chiều dài của kích thước N và điền vào mảng trong một lần.

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



Thay cho các nhận xét và nhầm lẫn, nếu bạn thực sự muốn nắm bắt các giá trị từ 1..N trong các ví dụ trên, có một số tùy chọn:

  1. nếu chỉ mục có sẵn, bạn chỉ cần tăng nó lên một (ví dụ ++i:).
  2. trong trường hợp chỉ mục không được sử dụng - và có thể là cách hiệu quả hơn - là tạo mảng của bạn nhưng làm cho N đại diện cho N + 1, sau đó chuyển ra phía trước.

    Vì vậy, nếu bạn mong muốn 100 số:

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





Tôi tin rằng điều này hữu ích khi mảng số đang được sử dụng cho dữ liệu không thể xử lý ở đầu nhận. (Giống như một mẫu HTML chỉ thay thế các giá trị.)
Neil Monroe

Tại sao ai đó sẽ làm điều này là để có một dãy số để điền vào danh sách thả xuống, cho người dùng lựa chọn từ 1 đến 10. Một mảng nhỏ bằng tay [1,2,3 ... 10] có ý nghĩa, nhưng nếu Đó là từ 1 đến 50? Nếu số cuối thay đổi thì sao?
Xì gà

@CigarDoug Tôi không nghi ngờ có một usecase, nhưng tôi đoán nó nhỏ. Tại sao một mảng các số lại cần thiết, thông thường khi lặp qua một mảng, một chỉ mục sẽ được sử dụng như một phần của cấu trúc vòng lặp - hoặc là một đối số cho hàm thân vòng lặp, hoặc một biến đếm - vì vậy việc giữ mảng các số có vẻ tầm thường để chỉ tạo một mảng có chiều rộng được chỉ định hoặc chỉ là một biến giữ giới hạn trên của mảng. Tôi có thể nghĩ về một vài trường hợp sử dụng, nhưng không có trường hợp nào được OP
vol7ron

4
Như tôi đã nói, tôi cần đưa ra một danh sách thả xuống với các số từ 1 đến 10. Đó là tất cả. Có một usecase, MY usecase. Đó là cách tôi tìm thấy trang này. Vì vậy, chỉ cần xây dựng một mảng bằng tay ít phức tạp hơn bất cứ điều gì tôi thấy ở đây. Vì vậy, yêu cầu của tôi không phải là yêu cầu của OP. Nhưng tôi có câu trả lời của tôi.
Xì gà

1
@ vol7ron Có một usecase, tôi cũng có một cái. Trong góc, trong phân trang, tôi muốn hiển thị các trang trong phần chân trang có thể nhấp được. Vì vậy, tôi lặp các phần tử trong chế độ xem với * ngFor = "let p of PagesCount". Bạn có một giải pháp tốt hơn cho điều đó? BTW, hãy kiểm tra stackoverflow.com/questions/36354325/ từ
Dalibor

186

Trong ES6 bạn có thể làm:

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

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

Chỉnh sửa: Thay đổi Array(45)để Array(N)kể từ khi bạn đã cập nhật các câu hỏi.

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


3
+1 vì đó là một O lớn hoàn toàn tốt hơn .join.splitphiên bản khó chịu - nhưng tôi vẫn nghĩ rằng vòng lặp khiêm tốn là tốt hơn.
Robin

Tôi đồng ý @Robin - Độ phức tạp của thuật toán sang một bên, vòng lặp khiêm tốn luôn dễ đọc hơn. Tuy nhiên, với sự ra đời của lambdas trong Java, tôi nghĩ mapsẽ sớm trở thành một tiêu chuẩn cho những thứ như thế này.
Nate

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

8
Tôi không hiểu tại sao .fill()cần thiết. Tôi thấy rằng đó là khi tôi kiểm tra thay thế của nút, nhưng vì Array(1)[0] === undefined, lệnh gọi điền vào () có gì khác biệt Array(1).fill(undefined)?
Đaminh

11
Đối với bất kỳ ai khác quan tâm, sự khác biệt giữa Mảng (N) và Mảng (N) .fill () được giải thích rõ ở đây
Dominic

108

Sử dụng phương thức Underscore _.range rất phổ biến

// _.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); // => []


Tuyệt vời. Chỉ cho tôi một dự án lớn không sử dụng dấu gạch dưới nào ...
Erez Cohen

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

Sau đó được gọi bởi

var foo = range(1, 5);

Không có cách tích hợp nào để thực hiện điều này trong Javascript, nhưng đó là một chức năng tiện ích hoàn toàn hợp lệ để tạo nếu bạn cần thực hiện nhiều lần.

Chỉnh sửa: Theo tôi, sau đây là một chức năng phạm vi tốt hơn. Có lẽ chỉ vì tôi thiên vị bởi LINQ, nhưng tôi nghĩ nó hữu ích hơn trong nhiều trường hợp. Số dặm của bạn có thể thay đổi.

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
Tôi thích điều này. Nếu bạn muốn đi thêm một dặm với nó, bạn có thể khai báo nó là Array.prototype.range = function (start, end) {...};. Sau đó, bạn có thể gọi phạm vi (x, y) trên bất kỳ đối tượng Array nào.
Zach Rattner

8
Thay vì làm cho nó trở thành một phương thức Arraythay vì Array.prototypekhông có lý do (thậm chí có thể được coi là khá ngu ngốc) để có phương thức này trên mỗi mảng.
adamse

9
Array.range(1, 5)có lẽ sẽ phù hợp hơn, nhưng có một cái gì đó tuyệt vời về văn bản [].range(1, 5).
MooGoo

"Thay vì biến nó thành một phương thức của Array thay vì Array.prototype" - Sự khác biệt là gì? Bạn có nghĩa là trên một mảng cụ thể?
pilau

3
@pilau Đúng như adamse nói, có vẻ lạ. Nếu đó là trên nguyên mẫu, bạn có thể nói foo = [1, 2, 3]; bar = foo.range(0, 10);. Nhưng đó chỉ là ... khó hiểu. bar = Array.range(0, 10)rõ ràng và rõ ràng hơn rất nhiều. Phạm vi không liên quan gì đến cá thể, vì vậy không có lý do gì để biến nó thành một phương thức cá thể.
Ian Henry

53

cách nhanh nhất để điền vào một Arrayv8 là:

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

kết quả sẽ là: [0, 1, 2, 3, 4]


Có cách nào để làm điều đó mà không cần thêm biến _
bluejayke 26/03/19

@bluejayke no :(
аlex dyky giác

khắc nghiệt, bạn có biết mã nguồn của .map là gì không? Tôi không chắc liệu nó có nhanh hơn vòng lặp for hay không, nhưng nếu không thì về mặt lý thuyết, chúng ta chỉ cần xác định Property và tạo một cái mới
bluejayke

49

Câu hỏi này có rất nhiều câu trả lời phức tạp, nhưng một câu hỏi đơn giản:

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

Ngoài ra, mặc dù phần trên ngắn (và gọn gàng) để viết, tôi nghĩ phần sau nhanh hơn một chút (cho độ dài tối đa:

127, Int8,

255, Uint8,

32.767, Int16,

65,535, Uint16,

2.147.483.647, Int32,

4.294.967.295, Uint32.

(dựa trên các giá trị số nguyên tối đa ), cũng ở đây nhiều hơn về Mảng được nhập ):

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

Mặc dù giải pháp này cũng không quá lý tưởng, bởi vì nó tạo ra hai mảng và sử dụng khai báo biến bổ sung "$" (không chắc chắn có cách nào để khắc phục điều đó bằng phương pháp này). Tôi nghĩ rằng giải pháp sau đây là cách nhanh nhất có thể để làm điều này:

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

Bất cứ lúc nào sau khi tuyên bố này được thực hiện, bạn có thể đơn giản sử dụng biến "mảng" trong phạm vi hiện tại;

Nếu bạn muốn tạo một chức năng đơn giản từ nó (với một số xác minh cơ bản):

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
);


vì vậy, với chức năng trên, "một lớp lót" siêu chậm ở trên trở thành siêu nhanh, thậm chí ngắn hơn:

range(1,14000);

@JVG nhưng không cho chức năng nhanh hơn?
bluejayke

Chính xác. Đây là một lót đơn giản mà tất cả mọi người đang tìm kiếm!
supersan

@supersan mặc dù nó siêu chậm :)
bluejayke

Javascript hiện đại với fillphương thức mới :Array(255).fill(0,0,255)
mã hóa

@cacoder nó nhanh như thế nào, nó tạo ra bao nhiêu mảng và bao nhiêu lần lặp?
bluejayke

42

Bạn có thể sử dụng điều này:

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

ví dụ

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

sẽ tạo mảng sau:

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

Ngoài ra, tại sao không new Array(10).join().split(',').map(function() {return ++arguments[1]});?
siêu

1
@Murplyx đối với một số trường hợp chức năng với các đối số bên trong sẽ không được tối ưu hóa bởi công cụ JS (đúng ngay cả với V8, xem jsperf.com/argument-vs-array-argument/2 )
nktssh

4
Đây là một giải pháp thú vị nhưng nó hoàn toàn không thực tế - phải phân tích cú pháp 3 lần (một lần join, một lần splitvà một lần cho điều bạn thực sự muốn làm) thật không hay - tôi biết rằng họ dường như không được ủng hộ vì một số lý do, nhưng sẽ tốt hơn nhiều nếu chỉ sử dụng một vòng lặp lỗi thời !
Robin

42

ES6 này sẽ thực hiện thủ thuật:

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

kiểm tra kết quả:

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


5
Thật

1
có, [...Array(N + 1).keys()].slice(1)sẽ mang lại 1..N
David G

Vì một số lý do, giải pháp này không hoạt động trong Phiên bản sản xuất từ ​​ứng dụng Expo (Reac -igen). [...Array(N + 1).keys()]mã này trả về một mảng trống, nhưng chỉ trong chế độ sản xuất, sử dụng chế độ phát triển hoạt động.
FabianoLothor

3
Câu .keys()trả lời đã được đưa ra từ nhiều năm trước và có hơn 500 lượt upvote. Câu trả lời của bạn thêm vào nó là gì?
Dan Dascalescu

39

Nếu bạn tình cờ sử dụng d3.js trong ứng dụng của bạn như tôi, D3 cung cấp chức năng trợ giúp thực hiện điều này cho bạn.

Vì vậy, để có được một mảng từ 0 đến 4, thật dễ dàng như sau:

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

và để có được một mảng từ 1 đến 5, như bạn đã yêu cầu:

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

Kiểm tra hướng dẫn này để biết thêm.


Nhận xét này đã cho tôi ý tưởng tìm kiếm hàm phạm vi () trong RamdaJS, đây là thư viện JS mà tôi đang làm việc với dự án hiện tại của mình. Hoàn hảo.
thái


38

Đây có lẽ là cách nhanh nhất để tạo ra một dãy số

Ngắn nhất

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

Nội tuyến

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

Nếu bạn muốn bắt đầu từ 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]

Bạn muốn một chức năng?

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]

TẠI SAO?

  1. while là vòng lặp nhanh nhất

  2. Cài đặt trực tiếp nhanh hơn push

  3. [] nhanh hơn new Array(10)

  4. nó ngắn ... nhìn mã đầu tiên. sau đó nhìn vào tất cả các chức năng khác ở đây.

Nếu bạn thích có thể không trực tiếp mà không cho

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

hoặc là

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

8
Sẽ là tốt hơn để sao lưu những tuyên bố này với điểm chuẩn. Hãy thử jsperf.com .
Matt Ball

2
lol jsperf ... xin vui lòng Matt chỉ vô hiệu hóa bạn không thích câu trả lời của tôi ngừng hạ thấp người khác của tôi ... stackoverflow.com/a/18344296/2450730 ... sử dụng console.time () hoặc cách nó được gọi là ... KHÔNG jsperf .
cocco

4
FYI: Như John Reisig xuất bản lần đầu cách đây vài năm - trên một số nền tảng (có nghĩa là cửa sổ: P) thời gian được đưa vào trình duyệt cứ sau 16ms. Ngoài ra còn có các vấn đề khác với việc đo thời gian thực hiện trong môi trường đa nhiệm. jsperf.com đã triển khai chạy thử nghiệm sao cho chúng đúng về mặt thống kê. Bạn có thể chạy console.time()để có được trực giác, nhưng để chứng minh, bạn cần jsperf.com VÀ nó cho bạn thấy kết quả trình duyệt chéo từ những người khác (phần cứng khác nhau, v.v.)
naugtur

3
@cocco điều này không chính xác:var a=[],b=N;while(b--){a[b]=a+1};
vintagexav 15/05/2015

5
@ cocco, trong khi không phải lúc nào cũng nhanh hơn các vòng lặp khác. Trong một số trình duyệt, vòng lặp giảm dần chậm hơn nhiều so với vòng lặp for, bạn không thể đưa ra tuyên bố chung về hiệu suất javascript như vậy bởi vì có rất nhiều triển khai với rất nhiều tối ưu hóa khác nhau. Tuy nhiên, nói chung tôi thích cách tiếp cận của bạn. ;-)
RobG

32

cách mới để điền Arraylà:

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

kết quả sẽ là: [0, 1, 2, 3, 4]


Đây là câu trả lời thực sự tốt, mặc dù về mặt kỹ thuật, câu hỏi là từ 1-N, không phải 0- (N-1)
bluejayke

31

Nếu bạn đang sử dụng lodash, bạn có thể sử dụng _.range :

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

Tạo một mảng các số (dương và / hoặc âm) tiến triển từ đầu đến, nhưng không bao gồm, kết thúc. Bước -1 được sử dụng nếu bắt đầu phủ định được chỉ định mà không có kết thúc hoặc bước. Nếu kết thúc không được chỉ định, nó được đặt thành bắt đầu bằng bắt đầu rồi đặt thành 0.

Ví dụ:

_.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

với ES6 bạn có thể làm:

// `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)

Vì các giá trị của mảng thực sự được điền bằng giải pháp này mapforEachsẽ hoạt động.
dontmentionthupup 22/11/19

27

Báo cáo tóm tắt cuối cùng .. Drrruummm Rolll -

Đây là mã ngắn nhất để tạo Mảng có kích thước N (ở đây là 10) mà không cần sử dụng ES6 . Phiên bản của Cocco ở trên gần nhưng không phải là ngắn nhất.

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

Nhưng người chiến thắng không thể tranh cãi của môn golf Code này (cạnh tranh để giải quyết một vấn đề cụ thể trong vài byte mã nguồn) là Niko Ruotsalainen . Sử dụng Array Con constructortoán tử trải ES6 . (Hầu hết cú pháp ES6 là typeScript hợp lệ, nhưng sau đây thì không. Vì vậy, hãy thận trọng khi sử dụng nó)

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

Tại sao lại bỏ phiếu? Danh sách câu trả lời dài khó theo dõi, nên nghĩ đến việc tóm tắt.
buổi sáng

Đây không phải là 0-10 sao? [... Mảng (10) .keys ()]
Greg

Webstorm gợi ý (mảng mới (10)). Phím (), có đúng không?
Chàng trai

(Mảng mới (10)). Các phím (), trả về ArrayIterator {}, không phải là mảng
sacco

Điều này tạo ra một biến toàn cầu a. Vòng lặp phải làfor(var a=[];n--;a[n]=n+1)
kube

20

Có một cách khác trong ES6, sử dụng Array.from , có 2 đối số, đầu tiên là một mảngLike (trong trường hợp này là một đối tượng có thuộc lengthtính) và thứ hai là một hàm ánh xạ (trong trường hợp này chúng ta ánh xạ mục vào chỉ mục của nó)

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

cái này ngắn hơn và có thể được sử dụng cho các chuỗi khác như tạo số chẵn

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

Ngoài ra, điều này có hiệu suất tốt hơn so với hầu hết các cách khác vì nó chỉ lặp một lần qua mảng. Kiểm tra đoạn trích để xem một số so sánh

// 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")


Này đó là gọn gàng, tôi thích nó. Tuy nhiên, nó không trả lại kết quả mà OP mong đợi. Để làm điều đó, nó cần phải được viết làArray.from({length:N}, (v,i) => i+1)
CervEd


16

Sử dụng các phương thức Array và =>cú pháp hàm mới từ tiêu chuẩn ES6 (chỉ Firefox tại thời điểm viết).

Bằng cách lấp đầy các lỗ với undefined:

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

Array.fromlần lượt "lỗ" vào undefinedđể Array.maplàm việc như mong đợi:

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

7
Tương tự, bạn cũng có thể thực hiện các thao tác sau trong ES6 : Array.from({length: N}, (v, k) => k).
XåpplI'-I0llwlg'I -

Cách tiếp cận của Xappli được ưa thích: Array.from đã được tạo cho gần như kịch bản chính xác này và nó ngụ ý gọi lại ánh xạ. Đó là một giải pháp tuyệt vời cho vấn đề chung là muốn sử dụng các phương thức Array trên một thứ gì đó giống như mảng, mà không cần dùng đến các cách tiếp cận dài dòng như Array.prototype.map.call, ví dụ như đối với NodeLists được trả về document.querySelectorAll. developer.mozilla.org/en/docs/Web/JavaScript/Reference/,
Josh từ Qaribou

Tôi đang cân nhắc điều này với cú pháp phạm vi gạch dưới và phạm vi đọc tốt hơn.
ooolala

Về mặt kỹ thuật, nó không Array.frombiến các giá trị thưa thớt thành không xác định. Thay vào đó Array(5)được gọi là một đối tượng đối số, lần lượt diễn giải các giá trị thưa thớt thành các giá trị không xác định :)
CervEd



12

Trong ES6:

Array.from({length: 1000}, (_, i) => i);

ES5:

Array.apply(0, {length: 1000}).map(function(x,i){return i});

10

Chỉ là một phiên bản ES6 khác .

Bằng cách sử dụng Array.fromđối số tùy chọn thứ hai:

Array.from (mảngLike [, mapFn [, thisArg]])

Chúng ta có thể xây dựng mảng được đánh số từ các Array(10)vị trí trống :

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

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


Điều này phức tạp hơn và chậm hơn ~ 10 lần [...Array(11).keys()].slice(1).
Dan Dascalescu

10

Có vẻ như hương vị duy nhất hiện tại không có trong danh sách các câu trả lời khá đầy đủ này là một trong đó có một máy phát điện; để khắc phục rằng:

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

có thể được sử dụng như vậy:

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

Điều thú vị ở đây là bạn không cần phải tăng ... Để lấy cảm hứng từ câu trả lời @ igor-shubin đã đưa ra, bạn có thể tạo ra một loạt các randoms rất dễ dàng:

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

Và thay vì một cái gì đó dài đắt tiền hoạt động như:

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

thay vào đó bạn có thể làm:

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

10

Bạn có thể sử dụng Array fill và ánh xạ từ Es6; giống như một vài người gợi ý trong câu trả lời mà họ đưa ra cho câu hỏi này. Dưới đây là một vài ví dụ:

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]

Tôi thích điều này bởi vì tôi thấy nó thẳng tiến và dễ dàng hơn.



9

Sử dụng ES6

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

Cảm ơn! Đây là câu trả lời tao nhã nhất theo ý kiến ​​của tôi! Người ta cũng có thể sử dụng Array.from(Array(n))nếu toán tử lây lan không được hỗ trợ.
Amit

Lúc đầu, tôi không biết tại sao bạn phải sử dụng toán tử trải rộng, nhưng sau đó tôi đã đọc phần sau về mapMDN : "Nó không được gọi là các phần tử bị thiếu của mảng (nghĩa là các chỉ mục chưa bao giờ được đặt, mà chỉ có đã bị xóa hoặc chưa bao giờ được gán một giá trị). "
battmanz

9

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

Trả về [0, 1, 2]. Rất giống với câu trả lời xuất sắc của Igor Shubin , nhưng với ít mánh khóe hơn (và dài hơn một ký tự).

Giải trình:

  • Array(3) // [undefined × 3]Tạo một mảng có độ dài n = 3. Thật không may, mảng này gần như vô dụng với chúng tôi, vì vậy chúng tôi phải
  • Array.apply(0,Array(3)) // [undefined, undefined, undefined]làm cho mảng lặp đi lặp lại. Lưu ý: null phổ biến hơn như đối số đầu tiên của ứng dụng nhưng ngắn hơn 0.
  • Object.keys(Array.apply(0,Array(3))) // ['0', '1', '2'] sau đó lấy các khóa của mảng (hoạt động vì Mảng là mảng typeof là một đối tượng có chỉ mục cho các khóa.
  • Object.keys(Array.apply(0,Array(3))).map(Number) // [0, 1, 2] và ánh xạ qua các phím, chuyển đổi chuỗi thành số.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.