Buat array dengan elemen yang sama diulang beberapa kali

323

Dalam Python, di mana [2]ada daftar, kode berikut memberikan hasil ini:

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

Apakah ada cara mudah untuk melakukan ini dengan array di JavaScript?

Saya menulis fungsi berikut untuk melakukannya, tetapi apakah ada sesuatu yang lebih pendek atau lebih baik?

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;
};
Curious2learn
sumber
4
Kemungkinan rangkap: stackoverflow.com/questions/1295584/…
Larry Battle

Jawaban:

52

Anda dapat melakukannya seperti ini:

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

Ini menggandakan array di setiap iterasi, sehingga dapat membuat array yang sangat besar dengan beberapa iterasi.


Catatan: Anda juga dapat banyak meningkatkan fungsi dengan menggunakan pushalih-alih concat, karena concatakan membuat array baru setiap iterasi. Seperti ini (ditunjukkan hanya sebagai contoh bagaimana Anda dapat bekerja dengan array):

function fillArray(value, len) {
  var arr = [];
  for (var i = 0; i < len; i++) {
    arr.push(value);
  }
  return arr;
}
Guffa
sumber
11
Ini jauh lebih efisien untuk mengalokasikan semua entri di muka, dengan arr = new Array(len);, lalu tetapkan kepada mereka dengan indeks dalam loop, yaitu arr[i] = value;. Dengan begitu Anda hanya membayar O (n) daripada harus terus merealokasi array saat itu tumbuh. Secara umum, selalu lebih baik untuk menghindari menumbuhkan array dengan menambahkan bila memungkinkan. Jika Anda tahu ukuran akhir, gunakan itu.
Tom Karzes
26
Array.from({length:5}).map(x => 2)
noobninja
1
@noobninja: solusi hebat; Anda harus memasukkannya kembali sebagai jawaban agar dapat dibatalkan.
jsalvata
693

Dalam ES6 menggunakan Array fill () metode

Array(5).fill(2)
//=> [2, 2, 2, 2, 2]
Niko Ruotsalainen
sumber
3
Internet Explorer dan Opera belum mendukungnya.
DenisKolodin
4
Node.js <= 3 tidak mendukung ini.
Junle Li
1
@DenisKolodin Opera Saat Ini tidak. Dan Edge juga. Lihat tabel-compat
Janus Troelsen
4
@Michael Anda bisa melakukannya dengan Array(5).fill([1,2,3]).flat(). Perhatikan bahwa flat () masih sangat eksperimental dan dukungan browser buruk.
Niko Ruotsalainen
3
Perhatikan bahwa argumen untuk filldievaluasi sekali, jadi Array(9).fill(someMutable)buat sembilan referensi ke someMutabledalam array (mutasi satu mutasi 'semuanya').
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]
Janus Troelsen
sumber
6
Pertanyaan konyol, tapi mengapa Array baru (10) .map tidak berfungsi?
blazkovicz
1
blazkovicz, lihat komentar zertosh tentang jawaban ini karena alasannya.
Ross Rogers
5
Dengan ES6, ini dapat "ditingkatkan" ke Array(...Array(10)).map(() => 5)dengan operator penyebaran atau juga keArray.from(Array(10)).map(() => 5)
Christophe Vidal
4
Menurut MDN , Anda bisa saja seperti ini:Array.from({length: 10}, () => 5);
Plusb Preco
2
@blazkovicz Array (10) membuat array lenght = 10tanpa properti enumerable. .maphanya bekerja pada properti enumerable. The .applymetode mengambil array ini, dan peta menjadi sebuah arguments array(sebuah objek array-seperti) yang akan diteruskan ke Arrayfungsi konstruktor. Array argumen tidak dapat jarang sehingga properti yang hilang diatur ke undefineddan menjadi enumerable. Sekarang kita dapat menggunakan .mapseperti yang dimaksudkan
CervEd
91

Anda dapat mencoba:

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

Pembaruan (01/06/2018) :

Sekarang Anda dapat memiliki satu set karakter yang berulang.

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

Catatan: Periksa lebih lanjut tentang isian (...) dan dari (...) untuk kompatibilitas dan dukungan browser.

Pembaruan (05/11/2019) :

Cara lain, tanpa menggunakan fillatau from, yang berfungsi untuk string dengan panjang berapa pun:

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

Sama seperti jawaban di atas . Menambah demi kelengkapan.

Vivek
sumber
1
Bagus. Terpendek dan sederhana.
Johann Echavarria
2
+1 untuk penanganan sederhana. Sayang sekali Anda tidak bisa membuat array string kosong dari itu. Terlepas dari itu sangat cerdas ...
Lebih cepat
1
Array (6) .join ('a'). Split ('a') memberi saya array string kosong.
Vivek
17
Ini hanya berfungsi untuk 1 string char, jadi itu tidak menjawab pertanyaan sepenuhnya.
az_
3
@ AlfonsoVergara: Dalam Javascript, String adalah tipe primitif (nilai-semantik); tidak ada cara untuk mendapatkan dua string untuk referensi data yang sama (karena string bukan referensi dalam Javascript; mereka nilai). Anda harus berhati-hati dengan referensi semantik dengan objek dan daftar, tetapi tidak dengan string.
Quuxplusone
36

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

atau buat array dengan nilai yang meningkat

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

Thomson
sumber
Bagus, 👍 ini adalah pendekatan terbaik jika Anda memerlukan elemen untuk dinamis
IliasT
Array.from({length:5}, i => 1)=> iadalah undefinedkarena itu merupakan nilai kosong Array.from({length:5}, (e, i)=>i)=> eadalah undefinedkarena itu mewakili nilai kosong. Seharusnya Array.from({length:5}, v => 1)danArray.from({length:5}, (v, i)=>i)
Rafal Enden
33

Di lodash tidak begitu buruk:

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

EDIT : Lebih baik lagi:

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

EDIT : Lebih baik lagi:

_.fill(Array(5), 2);
Droogan
sumber
3
_.times (panjang, _.constant (nilai))
user1533401
1
dari docs: _.fill (Array (3), 2); Yang tidak jauh dari ES6
kert
15

[c] * n dapat ditulis sebagai:

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

sehingga untuk [2] * 5

Array(6).join(1).split('').map(function(){return 2;})
sungai hong
sumber
Sebenarnya, bukankah Array (6) .join (2) .sit ('') lebih mudah? Mengapa Anda membutuhkan peta?
Angela
4
yang mengembalikan ["2", "2", "2", "2", "2"], alih-alih [2, 2, 2, 2, 2].
sungai hong
10

Anda juga dapat memperluas fungsionalitas Array seperti:

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] 

Saya harus mencatat bahwa memperluas fungsionalitas objek bawaan dapat menyebabkan masalah jika Anda bekerja dengan perpustakaan pihak ketiga. Selalu timbang ke dalam keputusan Anda.

Shmiddty
sumber
Perhatikan bahwa jika Anda melewatkan objek ke fillsetiap indeks dalam array akan merujuk ke objek yang sama, jadi mengubah satu akan mengubah semuanya. Ini tidak terlalu sulit untuk dipecahkan jika itu menjadi masalah.
Shmiddty
Saya tidak mengerti mengapa banyak pengguna javascript tidak mengetahui persyaratan untuk tidak membuat prototipe fungsi asli.
brooNo
2
Sebuah metode mengisi telah ditambahkan di ES6. Jadi saya tidak akan merekomendasikan menambahkan barang-barang Anda sendiri ke prototipe, Anda akan menimpa versi yang lebih cepat dan lebih mampu.
Janus Troelsen
1
@JanusTroelsen Untuk menghindari menimpa javascript atau perpustakaan pihak ketiga, Anda dapat memeriksa apakah ada sebelum menyatakannya. if (!Array.prototype.fill) { }
Oliver
1
@ JanusTroelsen Apa yang Anda maksud dengan "polyfill asli" ?. Saya menggunakan polifyll. Maksud saya: periksa untuk deteksi dan implementasi fitur jika tidak.
Oliver
5

Jika Anda perlu mengulangi array beberapa kali:

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

terinspirasi oleh jawaban ini

Henrik Christensen
sumber
di es6, Anda dapat melakukan "abc" .ulangi (3)
Janus Troelsen
4

Tidak ada cara yang lebih mudah. Anda perlu membuat lingkaran dan mendorong elemen ke dalam array.

Diodeus - James MacFarlane
sumber
Terima kasih! Sebelum saya menerima, apakah pushlebih baik atau concatlebih baik, dalam hal efisiensi?
Curious2learn
CONCAT perlu memeriksa dua array, PUSH hanya menambahkan elemen lain, jadi saya berharap PUSH lebih efisien secara umum, tetapi untuk DATA IDENTIK, saya pikir jawaban Guffa berhasil.
Diodeus - James MacFarlane
Tidak perlu loop, lihat jawaban saya.
Janus Troelsen
@ JanusTroelsen, tidak perlu mengulang kecuali Anda ingin cara yang efisien untuk melakukan tindakan ini. Milik Anda adalah salah satu dari implementasi lambat yang dapat Anda temukan. push () ke [] adalah yang tercepat.
chrilith
4

Gunakan fungsi ini:

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

Atau untuk versi yang lebih ringkas:

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

Atau untuk versi kari:

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

Anda dapat menggunakan fungsi ini dengan daftar:

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

>>> ['a', 'b', ...repeatElement('c', 5)]
['a', 'b', 'c', 'c', 'c', 'c', 'c']
Ken Mueller
sumber
4

Jika Anda perlu mengulang array, gunakan yang berikut ini.

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

akan kembali

Array(9) [ "a", "b", "c", "a", "b", "c", "a", "b", "c" ]
etoksin
sumber
oneliner hebat menggunakan array yang ada, apa yang saya butuhkan.
Gnerik
2

Satu kalimat lagi:

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

Fungsi ini menciptakan array elemen (panjang) di mana setiap elemen sama dengan (nilai) selama (nilai) adalah bilangan bulat atau string bilangan bulat. Angka desimal apa pun akan terpotong. Jika Anda ingin angka desimal, ganti "parseInt ( " dengan " 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;
}

Contoh:

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]
TxRegex
sumber
1

Saya punya masalah dengan metode yang disebutkan ketika saya menggunakan array seperti

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

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

Untuk mendapatkan ini saya menggunakan:

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;
};
Xaver
sumber
Ini bagus, tetapi mungkin harus dinamai cycle.
Drenmi
1

Saya menemukan ini hari ini ketika mencoba membuat array 2D tanpa menggunakan loop. Dalam retrospeksi, bergabung dengan array baru rapi; Saya mencoba memetakan array baru, yang tidak berfungsi karena peta melompati slot kosong.

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

Karakter "#" dapat berupa karakter tunggal apa pun yang valid. Angka 5 akan menjadi variabel untuk jumlah elemen yang Anda inginkan. 7 akan menjadi nilai yang Anda ingin isi dengan array Anda.

Metode pengisian baru lebih baik, dan ketika saya mengkodekan ini saya tidak tahu itu ada, saya juga tidak tahu bahwa pengulangan adalah es6; Saya akan menulis posting blog tentang menggunakan trik ini bersama-sama dengan mengurangi untuk melakukan hal-hal keren.

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

Gordon yang ajaib
sumber
1

Coba ini:

"avinash ".repeat(5).trim().split(" ");
Avinash
sumber
1

var finalAry = [..."2".repeat(5).split("")].map(Number);
console.log(finalAry);

Amaldev ps
sumber
0

Jika Anda menggunakan sabuk utlity seperti lodash / garis bawah Anda dapat melakukannya seperti ini :)

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

Dapat digunakan sebagai one-liner juga:

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

Meningkatkan pada jawaban Vivek , ini berfungsi untuk string dengan panjang berapa pun, untuk mengisi array dengan panjang n:Array(n+1).join('[string to be repeated][separator]').split('[separator]').slice(0, n)

Tigregalis
sumber
-1

Saya membutuhkan cara untuk mengulang / mengulangi array (dengan n item) m kali.

Misalnya, mendistribusikan daftar (orang) ke satu minggu / bulan. Katakanlah saya punya 3 nama, dan saya ingin mereka mengulanginya dalam seminggu:

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"]
akinuri
sumber