Aynı öğeyi birden çok kez tekrarlayan bir dizi oluşturma


323

[2]Liste olan Python'da aşağıdaki kod bu çıktıyı verir:

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

JavaScript'te bir dizi ile bunu yapmanın kolay bir yolu var mı?

Bunu yapmak için aşağıdaki işlevi yazdım, ama daha kısa veya daha iyi bir şey var mı?

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


Yanıtlar:


52

Bunu şu şekilde yapabilirsiniz:

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

Her yinelemede diziyi ikiye katlar, böylece birkaç yinelemeyle gerçekten büyük bir dizi oluşturabilir.


Not: Her yinelemede yeni bir dizi oluşturacağınız gibi , pushyerine işlevinizi de geliştirebilirsiniz . Bunun gibi (dizilerle nasıl çalışabileceğinizin bir örneği olarak gösterilir):concatconcat

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

11
Tüm girişleri önden ayırmak arr = new Array(len);, daha sonra bunlara döngüdeki dizine göre atamak çok daha etkilidir arr[i] = value;. Bu şekilde diziyi büyüdükçe yeniden tahsis etmek yerine sadece O (n) ödersiniz. Genel olarak, mümkün olduğunda ekleyerek dizileri büyütmekten kaçınmak her zaman daha iyidir. Son boyutu biliyorsanız, kullanın.
Tom Karzes

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

1
@noobninja: harika bir çözüm; yeniden oylanabilmesi için bir cevap olarak tekrar girmelisiniz.
jsalvata

693

ES6'da Array fill () yöntemini kullanarak

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

3
Internet Explorer ve Opera henüz desteklemiyor.
DenisKolodin

4
Node.js <= 3 bunu desteklemiyor.
Junle Li

1
@DenisKolodin Mevcut Opera yapar. Ve Edge de. Uygun tabloya
Janus Troelsen

4
@Michael ile yapabilirsiniz Array(5).fill([1,2,3]).flat(). Not ) (düz hala deneysel olan ve tarayıcı desteği zayıftır.
Niko Ruotsalainen

3
To argümanının bir fillkez değerlendirildiğine dikkat edin , bu nedenle dizide Array(9).fill(someMutable)dokuz referans oluşturur someMutable(birini değiştirerek 'hepsini' değiştirir).
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
Aptalca bir soru, ama neden yeni Array (10) .map çalışmıyor?
blazkovicz

1
blazkovicz, zertosh bu nedenle bu cevabın yorumuna bakın .
Ross Rogers

5
ES6 ile, bu durum Array(...Array(10)).map(() => 5)yayılma operatörü ile veya aynı zamanda "yükseltilebilir"Array.from(Array(10)).map(() => 5)
Christophe Vidal

4
MDN'ye göre , bunu şöyle yapabilirsiniz:Array.from({length: 10}, () => 5);
Plusb Preco

2
@blazkovicz Array (10), lenght = 10numaralandırılamayan özellikleri olmayan bir dizi oluşturur . .mapyalnızca numaralandırılabilir özellikler üzerinde çalışır. .applyYöntem, bu dizi alır ve bir içine eşler arguments arraygeçirilecek (bir dizi benzeri bir nesne) Arraybir kurucu. Arguments dizisi seyrek olamaz, bu nedenle eksik özellikler ayarlanır undefinedve numaralandırılır hale gelir. Şimdi .mapamaçlandığı gibi kullanabiliriz
CervEd

91

deneyebilirsin:

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

Güncelleme (01/06/2018) :

Artık bir dizi karakterin tekrarlanmasını sağlayabilirsiniz.

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

Not: hakkında daha kontrol edin dolgu (...) ve gelen (...) uyumluluk ve tarayıcı desteği için.

Güncelleme (11/05/2019) :

Herhangi bir uzunluktaki dize için çalışan fillveya kullanmadan başka bir yol from:

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

Yukarıdaki cevapla aynı . Bütünlük uğruna ekleme.


1
Güzel. En kısa ve basit.
Johann Echavarria

2
Kolay kullanım için +1. Bundan boş dizeler oluşturamayacağınız utanç verici. Bunun dışında çok akıllı ...
hızlı

1
Array (6) .join ('a'). Split ('a') bana boş dize dizisi verir.
Vivek

17
Bu sadece 1 karakter dizisi için geçerlidir, bu yüzden soruya tam olarak cevap vermez.
az_

3
@AlfonsoVergara: Javascript'te, String ilkel (değer-anlamsal) bir tiptir; aynı verilere başvurmak için iki dizeyi almanın bir yolu yoktur (çünkü dizeler Javascript'te referans değildir ; değerlerdir). Nesnelerle ve listelerle referans anlambilimine dikkat etmelisiniz, ancak dizelerle değil.
Quuxplusone

36

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

veya değeri artan dizi oluşturma

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


Güzel, dynamic dinamik öğeye ihtiyacınız varsa bu en iyi yaklaşımdır
IliasT

Array.from({length:5}, i => 1)=> iOlan bir undefinedboş değeri temsil eder çünkü Array.from({length:5}, (e, i)=>i)=> eolan undefinedboş bir değeri temsil eder çünkü. Bu olmalı Array.from({length:5}, v => 1)veArray.from({length:5}, (v, i)=>i)
Rafal Enden

33

Gelen lodash o kadar kötü değil:

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

EDIT : Daha da iyisi:

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

EDIT : Daha da iyisi:

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

3
_.times (uzunluk, _.sabit (değer))
user1533401

1
dokümanlardan: _. dolgu (Dizi (3), 2); Hangisi uzak olmayan ES6 dan
kertme

15

[c] * n şu şekilde yazılabilir:

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

için böylece [2] * 5

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

Aslında Array (6) .join (2) .split ('') daha kolay olmaz mıydı? Haritaya neden ihtiyacınız var?
Angela

4
[2, 2, 2, 2, 2] yerine ["2", "2", "2", "2", "2"] döndürür.
Brook Hong

10

Array'ın işlevselliğini şu şekilde de genişletebilirsiniz:

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] 

Üçüncü taraf kitaplıklarla çalışıyorsanız, yerleşik nesnelerin işlevlerini genişletmenin sorunlara neden olabileceğini unutmayın. Bunu her zaman kararlarınıza tartın.


Dizideki fillher dizine bir nesne iletirseniz aynı nesneye atıfta bulunacağını, bu nedenle bir nesneyi değiştirdiğinizde bunların tümünü değiştireceğinizi unutmayın. Bir sorun haline gelirse bunu çözmek çok zor değildir.
Shmiddty

Birçok javascript kullanıcısının neden yerel işlevleri prototip oluşturma gereksiniminin farkında olmadığını anlamıyorum.
brooNo

2
ES6'ya bir doldurma yöntemi eklendi. Bu yüzden prototipe kendi eşyalarınızı eklemenizi tavsiye etmem, daha hızlı ve daha yetenekli sürümün üzerine yazacaksınız.
Janus Troelsen

1
@JanusTroelsen Javascript veya üçüncü taraf kütüphanelerin üzerine yazmaktan kaçınmak için, bildirmeden önce var olup olmadığını kontrol edebilirsiniz. if (!Array.prototype.fill) { }
Oliver

1
@JanusTroelsen "Gerçek çoklu dolgu" ile ne demek istiyorsun? Bir polifil kullandım. Demek istediğim: Olmadığı takdirde özellik algılama ve uygulama olup olmadığını kontrol edin.
Oliver



4

Daha kolay bir yol yok. Bir döngü oluşturmalı ve öğeleri diziye itmelisiniz.


Teşekkürler! Kabul etmeden önce , verimlilik açısından daha pushiyi mi yoksa concatdaha iyi mi?
Curious2learn 19:12

CONCAT'in iki diziyi denetlemesi gerekiyor, PUSH sadece başka bir öğe ekliyor, bu yüzden PUSH'un genel olarak daha verimli olmasını beklerdim, ancak KİMLİK VERİLER için Guffa'nın cevabı çiviyi düşünüyorum.
Diodeus - James MacFarlane

Döngülere gerek yok, cevabımı görün.
Janus Troelsen

@JanusTroelsen, bu eylemi yapmak için etkili bir yol istemiyorsanız döngü yapmanıza gerek yok. Sizinki bulabileceğiniz daha yavaş öğütlerden biridir. en hızlı itme () seçeneğidir.
chrilith

4

Bu işlevi kullanın:

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

Veya daha kompakt bir sürüm için:

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

Veya köri kullanabilen bir sürüm için:

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

Bu işlevi bir listeyle kullanabilirsiniz:

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

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

4

Bir diziyi tekrarlamanız gerekirse aşağıdakileri kullanın.

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

dönecek

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

büyük oneliner var olan bir dizi kullanarak, ne gerek.
gneric

2

Başka bir astar:

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

1

Bu işlev, (value) bir tamsayı veya bir tamsayı dizgisi olduğu sürece her öğenin (value) değerine eşit olduğu bir (length) öğesi dizisi oluşturur. Ondalık sayılar kesilir. Ondalık sayılar istiyorsanız, "parseInt ( " yerine " 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;
}

Örnekler:

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

Gibi bir dizi kullandığımda belirtilen yöntemlerle ilgili sorunlar vardı

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

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

Bunu almak için kullanıyorum:

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

Bu güzel, ama muhtemelen adlandırılmalıdır cycle.
Drenmi

1

Bugün döngüler kullanmadan bir 2D dizi yapmaya çalışırken keşfettim. Retrospect'te, yeni bir diziye katılmak düzgün; Harita boş yuvaları atladığı gibi çalışmayan yeni bir dizi eşlemeyi denedim.

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

"#" Karakteri geçerli herhangi bir tek karakter olabilir. 5, istediğiniz öğe sayısı için bir değişken olacaktır. 7, dizinizi doldurmak istediğiniz değer olacaktır.

Yeni doldurma yöntemi daha iyidir ve bunu kodladığımda bunun var olduğunu bilmiyordum ve tekrarın es6 olduğunu da bilmiyordum; Havalı şeyler yapmak için indirimle birlikte bu hileyi birlikte kullanmayla ilgili bir blog yazısı yazacağım.

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




0

Lodash / alt çizgi gibi bir utlity kemer kullanıyorsanız bunu yapabilirsiniz :)

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

0

Tek astar olarak da kullanılabilir:

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

0

Vivek'in cevabını iyileştirerek , bu, n uzunluğunda bir diziyi doldurmak için herhangi bir uzunlukta dizgiler için çalışır:Array(n+1).join('[string to be repeated][separator]').split('[separator]').slice(0, n)


-1

Bir kez tekrarlamak için bir yol gerekli (n öğeleri ile) m kez.

Örneğin, bir listenin (kişilerin) bir hafta / aya ​​dağıtılması. Diyelim ki 3 ismim var ve bir hafta içinde tekrar etmelerini istiyorum:

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"]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.