Utwórz tablicę z tym samym elementem powtarzanym wiele razy

323

W Pythonie, gdzie [2]jest lista, następujący kod daje ten wynik:

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

Czy istnieje prosty sposób na zrobienie tego za pomocą tablicy w JavaScript?

Napisałem następującą funkcję, aby to zrobić, ale czy jest coś krótszego czy lepszego?

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
źródło
4
Możliwy duplikat: stackoverflow.com/questions/1295584/…
Larry Battle

Odpowiedzi:

52

Możesz to zrobić w następujący sposób:

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

Podwaja tablicę w każdej iteracji, dzięki czemu może stworzyć naprawdę dużą tablicę z kilkoma iteracjami.


Uwaga: Możesz również znacznie poprawić swoją funkcję, używając pushzamiast concat, ponieważ concatutworzy nową tablicę z każdą iteracją. W ten sposób (pokazany jako przykład pracy z tablicami):

function fillArray(value, len) {
  var arr = [];
  for (var i = 0; i < len; i++) {
    arr.push(value);
  }
  return arr;
}
Guffa
źródło
11
Znacznie wydajniej jest przydzielić wszystkie wpisy z góry, za pomocą arr = new Array(len);, a następnie przypisać je według indeksu w pętli, tj arr[i] = value;. W ten sposób płacisz tylko O ​​(n) zamiast konieczności ponownego przydzielania tablicy w miarę jej wzrostu. Zasadniczo zawsze lepiej jest unikać rozwijania tablic, dodając, jeśli to możliwe. Jeśli znasz ostateczny rozmiar, użyj go.
Tom Karzes,
26
Array.from({length:5}).map(x => 2)
noobninja
1
@noobninja: świetne rozwiązanie; powinieneś wpisać go ponownie jako odpowiedź, aby można było go ocenić.
jsalvata
692

W ES6 użyciem macierzy wypełnienia () Sposób

Array(5).fill(2)
//=> [2, 2, 2, 2, 2]
Niko Ruotsalainen
źródło
3
Internet Explorer i Opera jeszcze go nie obsługują.
DenisKolodin
4
Node.js <= 3 nie obsługuje tego.
Junle Li
1
@DenisKolodin Current Opera robi. I Edge też. Zobacz tabelę zgodności
Janus Troelsen,
4
@Michael Możesz to zrobić za pomocą Array(5).fill([1,2,3]).flat(). Zauważ, że flat () jest nadal bardzo eksperymentalny, a obsługa przeglądarki słaba.
Niko Ruotsalainen,
3
Zauważ, że argument do filljest oceniany raz, więc Array(9).fill(someMutable)tworzy dziewięć odwołań someMutablew tablicy (mutacja jednego powoduje mutację „wszystkich”).
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
źródło
6
Głupie pytanie, ale dlaczego nowa Array (10) .map nie działa?
blazkovicz
1
blezkowicz, zobacz komentarz Zertosha do tej odpowiedzi z tego powodu.
Ross Rogers
5
W przypadku ES6 można to „uaktualnić” do Array(...Array(10)).map(() => 5)operatora rozsiewania lubArray.from(Array(10)).map(() => 5)
Christophe Vidal
4
Według MDN można po prostu polubić:Array.from({length: 10}, () => 5);
Plusb Preco
2
@blazkovicz Array (10) tworzy tablicę lenght = 10bez żadnych wyliczalnych właściwości. .mapdziała tylko w przypadku wyliczalnych właściwości. .applySposób przy tej tablicy i mapuje w produkt arguments array(obiektu tablicy podobne), które mają być przekazane do Arrayfunkcji konstruktora. Tablica argumentów nie może być rzadka, więc brakujące właściwości są ustawiane undefinedi stają się wyliczalne. Teraz możemy używać .mapzgodnie z przeznaczeniem
CervEd
91

możesz spróbować:

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

Aktualizacja (01.06.2018) :

Teraz możesz mieć zestaw znaków powtarzających się.

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

Uwaga: Sprawdź więcej informacji o fill (...) i from (...) w celu uzyskania zgodności i obsługi przeglądarki.

Aktualizacja (05.11.2019) :

Innym sposobem, bez użycia filllub from, który działa dla ciągów dowolnej długości:

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

Taki sam jak powyższa odpowiedź . Dodawanie ze względu na kompletność.

Vivek
źródło
1
Miły. Najkrótszy i prostszy.
Johann Echavarria
2
+1 za prostą obsługę. Szkoda, że ​​nie można z tego stworzyć tablicy pustych ciągów. Poza tym bardzo sprytny ...
Quicker
1
Array (6) .join ('a'). Split ('a') daje mi tablicę pustych ciągów znaków.
Vivek
17
Działa to tylko dla 1 ciągów znaków, więc nie odpowiada całkowicie na pytanie.
az_
3
@AlfonsoVergara: W JavaScript, String jest typem pierwotnym (semantycznym); nie ma sposobu, aby uzyskać dwa ciągi odwołujące się do tych samych danych (ponieważ ciągi te nie są odwołaniami w JavaScript; są to wartości). Musisz uważać na semantykę odniesienia z obiektami i listami, ale nie z łańcuchami.
Quuxplusone
36

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

lub utwórz tablicę o rosnącej wartości

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

Thomson
źródło
Fajnie, 👍 jest to najlepsze podejście, jeśli potrzebujesz elementu do dynamiki
IliasT
Array.from({length:5}, i => 1)=> ijest, undefinedponieważ reprezentuje pustą wartość Array.from({length:5}, (e, i)=>i)=> ejest, undefinedponieważ reprezentuje pustą wartość. Powinno być Array.from({length:5}, v => 1)iArray.from({length:5}, (v, i)=>i)
Rafal Enden
33

W lodash nie jest tak źle:

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

EDYCJA : Jeszcze lepiej:

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

EDYCJA : Jeszcze lepiej:

_.fill(Array(5), 2);
Droogany
źródło
3
_. razy (długość, _. stała (wartość))
1533401
1
z dokumentów: _.fill (Array (3), 2); Który nie jest daleko od ES6
kert
15

[c] * n można zapisać jako:

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

więc dla [2] * 5

Array(6).join(1).split('').map(function(){return 2;})
strumyk hong
źródło
Czy Array (6) .join (2) .split ('') nie byłoby łatwiejsze? Dlaczego potrzebujesz mapy?
Angela
4
która zwraca [„2”, „2”, „2”, „2”, „2”], zamiast [2, 2, 2, 2, 2].
strumyk hong
10

Możesz także rozszerzyć funkcjonalność Array w taki sposób:

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] 

Należy zauważyć, że rozszerzenie funkcjonalności wbudowanych obiektów może powodować problemy, jeśli pracujesz z bibliotekami innych firm. Zawsze rozważ to przy podejmowaniu decyzji.

Shmiddty
źródło
Zauważ, że jeśli przekażesz obiekt do fillkażdego indeksu w tablicy, będzie on odnosił się do tego samego obiektu, więc zmiana jednego zmieni wszystkie. Nie jest to zbyt trudne do rozwiązania, jeśli stanie się problemem.
Shmiddty,
Nie rozumiem, dlaczego wielu użytkowników javascript nie zdaje sobie sprawy z wymogu, aby nie prototypować funkcji natywnych.
broo Nie
2
W ES6 dodano metodę wypełniania . Więc nie polecam dodawania własnych rzeczy do prototypu, zastąpisz szybszą i bardziej wydajną wersję.
Janus Troelsen
1
@JanusTroelsen Aby uniknąć zastąpienia bibliotek javascript lub bibliotek innych firm, możesz je sprawdzić przed jego zgłoszeniem. if (!Array.prototype.fill) { }
Oliver
1
@JanusTroelsen Co rozumiesz przez „prawdziwą polifill”? Użyłem polifilu. Mam na myśli: sprawdź wykrywanie funkcji i implementację, jeśli tak nie jest.
Oliver,
5

W przypadku, gdy trzeba powtórzyć tablicę kilka razy:

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

zainspirowany tą odpowiedzią

Henrik Christensen
źródło
w es6 możesz zrobić „abc” .repeat (3)
Janus Troelsen
4

Nie ma łatwiejszego sposobu. Musisz utworzyć pętlę i wcisnąć elementy do tablicy.

Diodeus - James MacFarlane
źródło
Dzięki! Zanim zaakceptuję, czy jest pushlepszy czy concatlepszy pod względem wydajności?
Curious2learn
CONCAT musi sprawdzić dwie tablice, PUSH po prostu dodaje kolejny element, więc spodziewałbym się, że PUSH będzie ogólnie bardziej wydajny, ale myślę, że w przypadku DANYCH IDENTYCZNYCH odpowiedź Guffa to pomniejsza.
Diodeus - James MacFarlane
Nie potrzeba pętli, zobacz moją odpowiedź.
Janus Troelsen
@JanusTroelsen, nie ma potrzeby zapętlania, chyba że chcesz efektywnego sposobu wykonania tej czynności. Twój jest jednym z wolniejszych impementacji, jakie możesz znaleźć. Push () do [] jest najszybszy.
Chrilith,
4

Użyj tej funkcji:

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

Lub dla bardziej kompaktowej wersji:

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

Lub dla wersji curry:

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

Możesz użyć tej funkcji z listą:

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

>>> ['a', 'b', ...repeatElement('c', 5)]
['a', 'b', 'c', 'c', 'c', 'c', 'c']
Ken Mueller
źródło
4

Jeśli chcesz powtórzyć tablicę, skorzystaj z poniższych.

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

wróci

Array(9) [ "a", "b", "c", "a", "b", "c", "a", "b", "c" ]
etoksyna
źródło
świetny oneliner przy użyciu istniejącej tablicy, czego potrzebowałem.
gneric
2

Kolejna linijka:

Array.prototype.map.call([]+Array(5+1),function(){ return '2'; })
Filip Hermans
źródło
1

Ta funkcja tworzy tablicę elementów (długość), w których każdy element jest równy (wartość), o ile (wartość) jest liczbą całkowitą lub ciągiem liczby całkowitej. Wszelkie liczby dziesiętne zostaną obcięte. Jeśli chcesz liczb dziesiętnych, zamień „parseInt ( ” na „ 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;
}

Przykłady:

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
źródło
1

Miałem problemy ze wspomnianymi metodami, kiedy korzystałem z tablicy podobnej do

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

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

Aby to uzyskać, używam:

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
źródło
To miłe, ale prawdopodobnie należy je nazwać cycle.
Drenmi
1

Odkryłem to dzisiaj, próbując stworzyć tablicę 2D bez użycia pętli. Patrząc wstecz, dołączenie do nowej tablicy jest miłe; Próbowałem zmapować nową tablicę, która nie działa, ponieważ mapa pomija puste miejsca.

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

Znak „#” może być dowolnym prawidłowym pojedynczym znakiem. Liczba 5 byłaby zmienną dla liczby wymaganych elementów. 7 będzie wartością, którą chcesz wypełnić tablicę.

Nowa metoda wypełniania jest lepsza, a kiedy ją kodowałem, nie wiedziałem, że istnieje, ani nie wiedziałem, że powtórzenie to es6; Zamierzam napisać wpis na blogu o używaniu tej sztuczki w tandemie z redukcją do robienia fajnych rzeczy.

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

Magiczny Gordon
źródło
1

Spróbuj tego:

"avinash ".repeat(5).trim().split(" ");
Avinash
źródło
1

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

Amaldev ps
źródło
0

Jeśli używasz paska narzędziowego, takiego jak lodash / podkreślenie, możesz to zrobić w ten sposób :)

let result = _.map(_.times(foo), function() {return bar})
Shane Rogers
źródło
0

Może być również stosowany jako jedna linijka:

function repeat(arr, len) {
    while (arr.length < len) arr = arr.concat(arr.slice(0, len-arr.length));
    return arr;
}
Sarsaparilla
źródło
0

Poprawiając odpowiedź Viveka , działa to na ciągi dowolnej długości, aby wypełnić tablicę o długości n:Array(n+1).join('[string to be repeated][separator]').split('[separator]').slice(0, n)

Tigregalis
źródło
-1

Potrzebowałem sposobu na powtórzenie / zapętlenie tablicy (z n elementów) m razy.

Na przykład dystrybucja listy (osób) do tygodnia / miesiąca. Powiedzmy, że mam 3 nazwiska i chcę, aby powtórzyły się za tydzień:

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
źródło