Tạo một mảng với cùng một phần tử được lặp lại nhiều lần


323

Trong Python, [2]danh sách ở đâu, đoạn mã sau cung cấp đầu ra này:

[2] * 5 # Outputs: [2,2,2,2,2]

Có tồn tại một cách dễ dàng để làm điều này với một mảng trong JavaScript không?

Tôi đã viết các chức năng sau đây để làm điều đó, nhưng có cái gì ngắn hơn hoặc tốt hơn?

var repeatelem = function(elem, n){
    // returns an array with element elem repeated n times.
    var arr = [];

    for (var i = 0; i <= n; i++) {
        arr = arr.concat(elem);
    };

    return arr;
};


Câu trả lời:


52

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

function fillArray(value, len) {
  if (len == 0) return [];
  var a = [value];
  while (a.length * 2 <= len) a = a.concat(a);
  if (a.length < len) a = a.concat(a.slice(0, len - a.length));
  return a;
}

Nó nhân đôi mảng trong mỗi lần lặp, vì vậy nó có thể tạo ra một mảng thực sự lớn với vài lần lặp.


Lưu ý: Bạn cũng có thể cải thiện chức năng của mình rất nhiều bằng cách sử dụng pushthay vì concat, như concatsẽ tạo ra một mảng mới mỗi lần lặp. Giống như thế này (được hiển thị như một ví dụ về cách bạn có thể làm việc với mảng):

function fillArray(value, len) {
  var arr = [];
  for (var i = 0; i < len; i++) {
    arr.push(value);
  }
  return arr;
}

11
Sẽ hiệu quả hơn nhiều khi phân bổ tất cả các mục lên phía trước arr = new Array(len);, sau đó gán cho chúng theo chỉ mục trong vòng lặp, nghĩa là arr[i] = value;. Bằng cách đó, bạn chỉ trả O (n) thay vì phải tiếp tục phân bổ lại mảng khi nó phát triển. Nói chung, tốt hơn hết là tránh tăng mảng bằng cách nối thêm khi có thể. Nếu bạn biết kích thước cuối cùng, sử dụng nó.
Tom Karze

26
Array.from({length:5}).map(x => 2)
noobninja

1
@noobninja: giải pháp tuyệt vời; bạn nên nhập lại dưới dạng câu trả lời để có thể nâng cấp.
jsalvata

693

Trong ES6 sử dụng phương thức Array fill ()

Array(5).fill(2)
//=> [2, 2, 2, 2, 2]

3
Internet Explorer và Opera chưa hỗ trợ.
DenisKolodin

4
Node.js <= 3 không hỗ trợ điều này.
Junle Li

1
@DenisKolodin Opera hiện tại nào. Và Edge cũng vậy. Xem bảng compat
Janus Troelsen

4
@Michael Bạn có thể làm điều đó với Array(5).fill([1,2,3]).flat(). Lưu ý rằng căn hộ () vẫn còn rất thử nghiệm và hỗ trợ trình duyệt kém.
Niko Ruotsalainen

3
Lưu ý rằng đối số fillđược đánh giá một lần, do đó Array(9).fill(someMutable)tạo ra chín tham chiếu someMutabletrong mảng (biến đổi một biến thể 'tất cả chúng').
Carl Smith

146
>>> Array.apply(null, Array(10)).map(function(){return 5})
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
>>> //Or in ES6
>>> [...Array(10)].map((_, i) => 5)
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]

6
Câu hỏi ngớ ngẩn, nhưng tại sao Array mới (10) .map không hoạt động?
blazkovicz


5
Với ES6, điều này có thể được "nâng cấp" lên Array(...Array(10)).map(() => 5)với toán tử trải hoặc cũng có thểArray.from(Array(10)).map(() => 5)
Barshe Vidal

4
Dựa theo MDN , bạn có thể chỉ như thế này:Array.from({length: 10}, () => 5);
Plusb Preco

2
@blazkovicz Array (10) tạo ra một mảng lenght = 10mà không có bất kỳ thuộc tính nào. .mapchỉ hoạt động trên vô số tài sản. Các .applyphương pháp lấy mảng này, và bản đồ nó thành một arguments array(một đối tượng mảng tương tự) được truyền cho Arrayhàm xây dựng. Mảng đối số không thể thưa thớt để các thuộc tính bị thiếu được thiết lập undefinedvà trở thành vô số. Bây giờ chúng ta có thể sử dụng .mapnhư dự định
CervEd

91

bạn co thể thử:

Array(6).join('a').split(''); // returns ['a','a','a','a','a'] (5 times)

Cập nhật (01/06/2018) :

Bây giờ bạn có thể có một bộ ký tự lặp lại.

new Array(5).fill('a'); // give the same result as above;
// or
Array.from({ length: 5 }).fill('a')

Lưu ý: Kiểm tra thêm về điền (...)từ (...) để biết khả năng tương thích và hỗ trợ trình duyệt.

Cập nhật (05/11/2019) :

Một cách khác, không sử dụng fillhoặc from, hoạt động cho chuỗi có độ dài bất kỳ:

Array.apply(null, Array(3)).map(_ => 'abc') // ['abc', 'abc', 'abc']

Tương tự như câu trả lời trên . Thêm cho sự hoàn thiện.


1
Đẹp. Ngắn nhất và đơn giản hơn.
Johann Echavarria

2
+1 để xử lý đơn giản. Một sự xấu hổ là bạn không thể tạo ra một chuỗi các chuỗi trống từ đó. Ngoài ra rất thông minh ...
Nhanh hơn

1
Mảng (6) .join ('a'). Split ('a') cung cấp cho tôi mảng chuỗi rỗng.
Vivek

17
Điều này chỉ hoạt động cho 1 chuỗi char, vì vậy nó không trả lời hoàn toàn câu hỏi.
az_

3
@AlfonsoVergara: Trong Javascript, String là loại nguyên thủy (giá trị ngữ nghĩa); không có cách nào để có hai chuỗi tham chiếu cùng một dữ liệu (vì các chuỗi không tham chiếu trong Javascript; chúng là các giá trị). Bạn phải coi chừng ngữ nghĩa tham chiếu với các đối tượng và danh sách, nhưng không phải với các chuỗi.
Quuxplusone

36

Array.from({length:5}, i => 1) // [1, 1, 1, 1, 1]

hoặc tạo mảng với giá trị tăng dần

Array.from({length:5}, (e, i)=>i) // [0, 1, 2, 3, 4]


Thật tuyệt, đây là cách tiếp cận tốt nhất nếu bạn cần yếu tố để năng động
IliasT

Array.from({length:5}, i => 1)=> iundefinedvì nó đại diện cho giá trị trống Array.from({length:5}, (e, i)=>i)=> eundefinedvì nó đại diện cho giá trị trống. Nó nên Array.from({length:5}, v => 1)Array.from({length:5}, (v, i)=>i)
Rafal Enden

33

Trong lodash nó không quá tệ:

_.flatten(_.times(5, function () { return [2]; }));
// [2, 2, 2, 2, 2]

EDIT : Thậm chí tốt hơn:

_.times(5, _.constant(2));
// [2, 2, 2, 2, 2]

EDIT : Thậm chí tốt hơn:

_.fill(Array(5), 2);

3
_.times (chiều dài, _.constant (giá trị))
user1533401 17/11/14

1
từ các tài liệu: _.fill (Mảng (3), 2); Đó là không xa ES6
Kert

15

[c] * n có thể được viết như:

Array(n+1).join(1).split('').map(function(){return c;})

vì vậy đối với [2] * 5

Array(6).join(1).split('').map(function(){return 2;})

Trên thực tế, Array (6) .join (2) .split ('') có dễ dàng hơn không? Tại sao bạn cần bản đồ?
Angela

4
trả về ["2", "2", "2", "2", "2"], thay vì [2, 2, 2, 2, 2].
brook hong

10

Bạn cũng có thể mở rộng chức năng của Array như vậy:

Array.prototype.fill = function(val){
    for (var i = 0; i < this.length; i++){
        this[i] = val;
    }
    return this;
};
// used like:
var arry = new Array(5)​.fill(2);
// or
var arry = new Array(5);
arry.fill(2);


console.log(arry);​ //[2, 2, 2, 2, 2] 

Tôi nên lưu ý rằng việc mở rộng chức năng của các đối tượng tích hợp có thể gây ra sự cố nếu bạn đang làm việc với các thư viện của bên thứ 3. Luôn cân nhắc điều này vào quyết định của bạn.


Lưu ý rằng nếu bạn truyền một đối tượng vào filltừng chỉ mục trong mảng sẽ tham chiếu đến cùng một đối tượng, vì vậy việc thay đổi một đối tượng sẽ thay đổi tất cả chúng. Điều này không quá khó để giải quyết nếu nó trở thành một vấn đề.
Shmiddty

Tôi không hiểu tại sao nhiều người dùng javascript không biết về yêu cầu không phải là nguyên mẫu gốc.
brooKhông

2
Một phương thức điền đã được thêm vào trong ES6. Vì vậy, tôi không khuyên bạn nên thêm nội dung của riêng bạn vào nguyên mẫu, bạn sẽ ghi đè lên phiên bản nhanh hơn và có khả năng hơn.
Janus Troelsen

1
@JanusTroelsen Để tránh ghi đè thư viện javascript hoặc bên thứ 3, bạn có thể kiểm tra xem có tồn tại trước khi khai báo không. if (!Array.prototype.fill) { }
Oliver

1
@JanusTroelsen Ý của bạn là "polyfill thực" nghĩa là gì?. Tôi đã sử dụng một polifyll. Ý tôi là: kiểm tra phát hiện và thực hiện tính năng trong trường hợp không.
Oliver


5

Trong trường hợp bạn cần lặp lại một mảng nhiều lần:

var arrayA = ['a','b','c'];
var repeats = 3;
var arrayB = Array.apply(null, {length: repeats * arrayA.length})
        .map(function(e,i){return arrayA[i % arrayA.length]});
// result: arrayB = ['a','b','c','a','b','c','a','b','c']

lấy cảm hứng từ câu trả lời này


trong es6, bạn có thể thực hiện "abc" .repeat (3)
Janus Troelsen

4

Không có cách nào dễ dàng hơn. Bạn cần tạo một vòng lặp và đẩy các phần tử vào mảng.


Cảm ơn! Trước khi tôi chấp nhận, pushtốt hơn hay concattốt hơn, về mặt hiệu quả?
Curious2learn

CONCAT cần kiểm tra hai mảng, PUSH chỉ cần thêm một yếu tố khác, vì vậy tôi hy vọng PUSH sẽ hiệu quả hơn nói chung, nhưng đối với DỮ LIỆU IDENTICS tôi nghĩ rằng câu trả lời của Guffa đã đóng đinh nó.
Diodeus - James MacFarlane

Không cần vòng lặp, xem câu trả lời của tôi.
Janus Troelsen

@JanusTroelsen, không cần phải lặp lại trừ khi bạn muốn một cách hiệu quả để thực hiện hành động này. Của bạn là một trong những sự chậm trễ mà bạn có thể tìm thấy. đẩy () đến [] là nhanh nhất.
chrilith 6/03/2015

4

Sử dụng chức năng này:

function repeatElement(element, count) {
    return Array(count).fill(element)
}
>>> repeatElement('#', 5).join('')
"#####"

Hoặc cho phiên bản nhỏ gọn hơn:

const repeatElement = (element, count) =>
    Array(count).fill(element)
>>> repeatElement('#', 5).join('')
"#####"

Hoặc cho phiên bản cà ri có thể:

const repeatElement = element => count =>
    Array(count).fill(element)
>>> repeatElement('#')(5).join('')
"#####"

Bạn có thể sử dụng chức năng này với một danh sách:

const repeatElement = (element, count) =>
    Array(count).fill(element)

>>> ['a', 'b', ...repeatElement('c', 5)]
['a', 'b', 'c', 'c', 'c', 'c', 'c']

4

Nếu bạn cần lặp lại một mảng, sử dụng như sau.

Array.from({ length: 3 }).fill(['a','b','c']).flat()

sẽ trở lại

Array(9) [ "a", "b", "c", "a", "b", "c", "a", "b", "c" ]

oneliner tuyệt vời bằng cách sử dụng một mảng hiện có, những gì tôi cần.
gneric

2

Một lớp lót khác:

Array.prototype.map.call([]+Array(5+1),function(){ return '2'; })

1

Hàm này tạo ra một mảng gồm các phần tử (độ dài) trong đó mỗi phần tử bằng (giá trị) miễn là (giá trị) là một số nguyên hoặc chuỗi của một số nguyên. Bất kỳ số thập phân sẽ được cắt ngắn. Nếu bạn muốn số thập phân, thay thế "parseInt ( " bằng " parseFloat ( "

function fillArray(length, intValue) {
     var vals = (new Array(length + 1)).join(intValue + '|').split('|').slice(0,length);
     for(var i = 0; i < length; i += 1) {
         vals[i] = parseInt(vals[i]);
     }
     return vals;
}

Ví dụ:

fillArray(5, 7) // returns [7,7,7,7,7]
fillArray(5, 7.5) // returns [7,7,7,7,7]
fillArray(5, 200) // returns [200,200,200,200,200]

1

Tôi gặp vấn đề với các phương thức được đề cập khi tôi sử dụng một mảng như

var array = ['foo', 'bar', 'foobar'];
var filled = array.fill(7);

//filled should be ['foo', 'bar', 'foobar', 'foo', 'bar', 'foobar', 'foo']

Để có được điều này tôi đang sử dụng:

Array.prototype.fill = function(val){
    var l = this.length;
    if(l < val){
        for(var i = val-1-l; i >= 0; i--){
            this[i+l] = this[i % l];
        }
    }
    return this;
};

Điều này là tốt đẹp, nhưng có lẽ nên được đặt tên cycle.
Drenmi

1

Tôi phát hiện ra điều này ngày hôm nay trong khi cố gắng tạo một mảng 2D mà không sử dụng các vòng lặp. Nhìn lại, tham gia một mảng mới là gọn gàng; Tôi đã thử ánh xạ một mảng mới, không hoạt động khi bản đồ bỏ qua các vị trí trống.

"#".repeat(5).split('').map(x => 0)

Char "#" có thể là bất kỳ ký tự đơn hợp lệ nào. 5 sẽ là một biến cho số lượng phần tử bạn muốn. 7 sẽ là giá trị bạn muốn điền vào mảng của bạn.

Phương thức điền mới tốt hơn và khi tôi mã hóa nó, tôi không biết nó tồn tại, tôi cũng không biết lặp lại là es6; Tôi sẽ viết một bài đăng trên blog về việc sử dụng thủ thuật này song song với việc giảm bớt để làm những điều tuyệt vời.

http://jburger.us.to/2016/07/14/feftally-create-a-2d-array/


1

Thử cái này:

"avinash ".repeat(5).trim().split(" ");


0

Nếu bạn đang sử dụng một vành đai tiện dụng như lodash / gạch dưới, bạn có thể làm như thế này :)

let result = _.map(_.times(foo), function() {return bar})

0

Có thể được sử dụng như một lớp lót quá:

function repeat(arr, len) {
    while (arr.length < len) arr = arr.concat(arr.slice(0, len-arr.length));
    return arr;
}

0

Cải thiện câu trả lời của Vivek , điều này hoạt động đối với các chuỗi có độ dài bất kỳ, để điền vào một mảng có độ dài n:Array(n+1).join('[string to be repeated][separator]').split('[separator]').slice(0, n)


-1

Tôi cần một cách để lặp lại / lặp một mảng (với n mục) m lần.

Ví dụ: phân phối danh sách (của người) đến một tuần / tháng. Giả sử tôi có 3 tên và tôi muốn chúng lặp lại sau một tuần:

fillArray(["Adam", "Blair", "Curtis"], 7); // returns ["Adam", "Blair", "Curtis", "Adam", "Blair", "Curtis", "Adam"]

function fillArray(pattern, count) {
    let result = [];
    if (["number", "string"].includes(typeof pattern)) {
        result = new Array(5);
        result.fill(pattern);
    }
    else if (pattern instanceof Array) {
        for (let i = 0; i < count; i++) {
            result = result.concat(pattern);
        }
        result = result.slice(0, count);
    }
    return result;
}

fillArray("a", 5);        // ["a", "a", "a", "a", "a"]
fillArray(1, 5);          // [1, 1, 1, 1, 1]
fillArray(["a", "b"], 5); // ["a", "b", "a", "b", "a"]
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.