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


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

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]

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]

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ść.


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]


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

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

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.


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ą


w es6 możesz zrobić „abc” .repeat (3)
Janus Troelsen

4

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


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

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

świetny oneliner przy użyciu istniejącej tablicy, czego potrzebowałem.
gneric


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]

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

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/




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

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

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)


-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"]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.