Jak utworzyć tablicę zawierającą 1… N


1161

Poszukuję alternatywnych sposobów na utworzenie tablicy JavaScript zawierającej od 1 do N, gdzie N jest znane tylko w czasie wykonywania.

var foo = [];

for (var i = 1; i <= N; i++) {
   foo.push(i);
}

Dla mnie wydaje się, że powinien istnieć sposób na zrobienie tego bez pętli.


224
Po przeczytaniu całej strony doszedłem do wniosku, że twoja prosta pętla for jest najprostszą, najbardziej czytelną i najmniej podatną na błędy.
Kokodoko

Jeśli ktoś potrzebuje czegoś bardziej zaawansowanego, stworzyłem bibliotekę node.js, która robi to dla liczb, liter, zakresów ujemnych / dodatnich itp . Github.com/jonschlinkert/fill-range . Jest używany w github.com/jonschlinkert/braces do rozwijania nawiasów klamrowych i github.com/jonschlinkert/micromatch do wzorców
globów

1
Powinieneś edytować, aby powiedzieć „Jak utworzyć tablicę o długości N” zamiast „... zawierającej 1 ... N”, to ostatnie sugeruje, że będą elementy o wartościach od 1 do N
Steven Landow

7
@StevenLandow, dlaczego OP powinna zmieniać nazwę? On chce tablicy z wartościami 1 ... N?
Andre Elrico,

Dobre pytanie, dobry tytuł, (trochę) głupie odpowiedzi.
Bitterblue,

Odpowiedzi:


381

Jeśli dostanę to, czego szukasz, potrzebujesz tablicy liczb 1..n, którą możesz później zapętlić.

Jeśli to wszystko, czego potrzebujesz, możesz to zrobić zamiast tego?

var foo = new Array(45); // create an empty array with length 45

wtedy, gdy chcesz go użyć ... (niezoptymalizowany, na przykład)

for(var i = 0; i < foo.length; i++){
  document.write('Item: ' + (i + 1) + ' of ' + foo.length + '<br/>'); 
}

np. jeśli nie musisz przechowywać niczego w tablicy, potrzebujesz tylko pojemnika o odpowiedniej długości, nad którym możesz iterować ... to może być łatwiejsze.

Zobacz to w akcji tutaj: http://jsfiddle.net/3kcvm/


4
pod wrażeniem, że udało mi się sformułować moje pytanie lepiej niż ja, naprawdę masz rację, ponieważ po refleksji potrzebuję tylko szeregu liczb, które mogę później zapętlić :) Dziękuję za odpowiedź.
Godders,

147
@Godders: Jeśli tego właśnie szukasz, dlaczego potrzebujesz tablicy? Wystarczy proste, var n = 45;a następnie zapętlenie od 1..n.
casablanca

3
@Godders - Uwaga: jeśli chcesz zmniejszyć rozmiar tablicy po jej utworzeniu do długości M, po prostu użyj foo.length = M--- Informacje o odcięciu zostaną utracone. Zobacz to w akcji ==> jsfiddle.net/ACMXp
Peter

24
Naprawdę nie rozumiem, dlaczego ta odpowiedź ma nawet głosy poparcia ... szczególnie, gdy sam OP zgadza się, że nie ma sensu w kilku powyższych komentarzach, ponieważ mógł po prostu to zrobić var n = 45;.
plalx

72
@scunliffe: Należy pamiętać, że new Array(45);to nie „tworzy tablicę 45 elementów” (w tym samym znaczeniu co [undefined,undefined,..undefined]robi). Raczej „tworzy pustą tablicę o długości = 45” ( [undefined x 45]), tak samo jak var foo = []; foo.length=45;. Dlatego forEachi mapnie będzie miało zastosowania w tym przypadku.
tomalec

1307

W ES6 przy użyciu metod Array from () i keys () .

Array.from(Array(10).keys())
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Krótsza wersja z operatorem rozkładania .

[...Array(10).keys()]
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

74
Tylko uwaga, to zawsze zaczyna się od 0. Będziesz musiał połączyć łańcuch mapz tablicą, aby dostosować wartości ( [...Array(10).keys()].map(x => x++);), aby zacząć od 1
Sterling Archer

32
Wystarczy zmienić map(x => x++)na map(x => ++x)ze względu na przyrost pierwszeństwa po zwrocie wartości :)
Brock

92
Eee co !? Dlaczego, mapkiedy możesz po prostu slice? [...Array(N+1).keys()].slice(1)
Robin

19
Lub nie używaj keysi tylko 1 mapa ->Array.from(Array(10)).map((e,i)=>i+1)
yonatanmn

60
Lub nie używaj klawiszy i mapy i po prostu przekaż funkcję mapowania dofrom Array.from(Array(10), (e,i)=>i+1)
Fabio Antunes

844

Możesz to zrobić:

var N = 10; 
Array.apply(null, {length: N}).map(Number.call, Number)

wynik: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

lub z losowymi wartościami:

Array.apply(null, {length: N}).map(Function.call, Math.random)

wynik: [0,7082694901619107, 0,9572225909214467, 0,8586748542729765, 0,8653848143294454, 0,008339877473190427, 0,9911756622605026, 0,8133423360995948, 0,8377588465809822, 0,557758303636454, 0,0753 930 955 364, 0,0753 930 955 0,475

Wyjaśnienie

Po pierwsze, zwróć uwagę na Number.call(undefined, N)to Number(N), co po prostu zwraca N. Wykorzystamy ten fakt później.

Array.apply(null, [undefined, undefined, undefined])jest równoważne z Array(undefined, undefined, undefined), który tworzy tablicę trzyelementową i przypisuje undefineddo każdego elementu.

Jak możesz to uogólnić na N elementów? Zastanów się, jak to Array()działa, co wygląda mniej więcej tak:

function Array() {
    if ( arguments.length == 1 &&
         'number' === typeof arguments[0] &&
         arguments[0] >= 0 && arguments &&
         arguments[0] < 1 << 32 ) {
        return [  ];  // array of length arguments[0], generated by native code
    }
    var a = [];
    for (var i = 0; i < arguments.length; i++) {
        a.push(arguments[i]);
    }
    return a;
}

Od ECMAScript 5 , Function.prototype.apply(thisArg, argsArray)przyjmuje również kaczki wpisany tablicowej obiekt jako drugi parametr. Jeśli wywołamy Array.apply(null, { length: N }), to się uruchomi

function Array() {
    var a = [];
    for (var i = 0; i < /* arguments.length = */ N; i++) {
        a.push(/* arguments[i] = */ undefined);
    }
    return a;
}

Teraz mamy tablicę N- element, z każdym elementem ustawionym na undefined. Kiedy .map(callback, thisArg)go wywołamy, każdy element zostanie ustawiony na wynik callback.call(thisArg, element, index, array). Dlatego [undefined, undefined, …, undefined].map(Number.call, Number)odwzorowałby każdy element na (Number.call).call(Number, undefined, index, array), który jest taki sam, jak Number.call(undefined, index, array), jak zaobserwowaliśmy wcześniej, ocenia index. To uzupełnia tablicę, której elementy są takie same jak ich indeks.

Po co męczyć się Array.apply(null, {length: N})zamiast po prostu Array(N)? Po tym wszystkim, oba wyrażenia spowoduje AN N -elementowe tablicę niezdefiniowanych elementów. Różnica polega na tym, że w pierwszym wyrażeniu każdy element jest jawnie ustawiony na niezdefiniowany, podczas gdy w drugim wyrażeniu każdy element nigdy nie był ustawiony. Zgodnie z dokumentacją .map():

callbackjest wywoływany tylko dla indeksów tablicy, którym przypisano wartości; nie jest wywoływany dla indeksów, które zostały usunięte lub którym nigdy nie przypisano wartości.

Dlatego Array(N)jest niewystarczający; Array(N).map(Number.call, Number)spowodowałoby niezainicjowanego matrycy o długości N .

Zgodność

Ponieważ ta technika opiera się na zachowaniu Function.prototype.apply()określonym w ECMAScript 5, nie będzie działać w przeglądarkach starszych niż ECMAScript 5, takich jak Chrome 14 i Internet Explorer 9.


62
+1 za spryt, ale pamiętaj, że jest to rząd wielkości POWOLI niż prymityw dla pętli: jsperf.com/array-magic-vs-for
warpech

7
Bardzo sprytne - prawdopodobnie zbyt. Wykorzystanie faktu, że Function.prototype.callpierwszym parametrem jest thisobiekt do mapowania bezpośrednio nad Array.prototype.mapparametrem iteratora, ma pewną błyskotliwość.
Noah Freitas,

14
To jest naprawdę, bardzo sprytne (granice nadużywania JS). mapMoim zdaniem naprawdę ważnym wglądem jest osobliwość nieprzypisanych wartości. Inną wersją (i być może nieco jaśniejszą, choć dłuższą) jest: Array.apply(null, { length: N }).map(function(element, index) { return index; })
Ben Reich

6
@BenReich Jeszcze lepiej (pod względem poziomów nadużyć JS): Array.apply(null, new Array(N)).map(function(_,i) { return i; }) lub, w przypadku es6 i funkcji strzałek, jeszcze krócej: Array.apply(null, new Array(N)).map((_,i) => i)
oddy

1
JEŻELI to zwraca tablicę, która zaczyna się od 1, w rzeczywistości odpowiedziałaby na pytanie OP
Hai Phan

479

Wiele sposobów korzystania z ES6

Korzystanie z ...metody spread operator ( ) i keys

[ ...Array(N).keys() ].map( i => i+1);

Wypełnij / mapę

Array(N).fill().map((_, i) => i+1);

Array.from

Array.from(Array(N), (_, i) => i+1)

Array. From and { length: N }hack

Array.from({ length: N }, (_, i) => i+1)

Uwaga na temat formy uogólnionej

Wszystkie powyższe formy tablic może produkować zerowana do prawie każdej żądanej wartości poprzez zmianę i+1ekspresji wymagane (np i*2, -i, 1+i*2, i%2i etc). Jeśli wyrażenie może być wyrażone przez jakąś funkcję, fwówczas pierwsza forma staje się po prostu

[ ...Array(N).keys() ].map(f)

Przykłady:

Array.from({length: 5}, (v, k) => k+1); 
// [1,2,3,4,5]

Ponieważ tablica jest inicjowana undefineddla każdej pozycji, wartością v będzieundefined

Przykład przedstawiający wszystkie formularze

Bardziej ogólny przykład z niestandardową funkcją inicjalizacji, ftj

[ ...Array(N).keys() ].map((i) => f(i))

lub nawet prościej

[ ...Array(N).keys() ].map(f)


33
Najlepsza odpowiedź IMHO. Zobacz także developer.mozilla.org/de/docs/Web/JavaScript/Reference/…
le_m

5
Użyj k ++ dla tablic zaczynających się od 0
Borgboy

1
Jeśli chcesz zwiększyć, nie używaj k++, używaj ++k.
Alex

4
Uważaj Array.from nie jest obsługiwany w IE, chyba że go wypełniasz.
Lauren

2
Aby uszczęśliwić kompilator TS, rozważ zamianę nieużywanego parametru na lodash: Array.from ({length: 5}, (_, k) => k + 1);
Journeycorner

296

Tablice z natury zarządzają swoimi długościami. Podczas ich przechodzenia ich indeksy mogą być przechowywane w pamięci i przywoływane w tym punkcie. Jeśli trzeba znać indeks losowy, indexOfmożna zastosować tę metodę.


To powiedziawszy, dla twoich potrzeb możesz po prostu zadeklarować tablicę o określonym rozmiarze:

var foo = new Array(N);   // where N is a positive integer

/* this will create an array of size, N, primarily for memory allocation, 
   but does not create any defined values

   foo.length                                // size of Array
   foo[ Math.floor(foo.length/2) ] = 'value' // places value in the middle of the array
*/


ES6

Rozpowszechnianie się

Korzystanie z operatora spread ( ...) i keysmetody umożliwia utworzenie tymczasowej tablicy o rozmiarze N w celu wygenerowania indeksów, a następnie nowej tablicy, którą można przypisać do zmiennej:

var foo = [ ...Array(N).keys() ];

Wypełnij / mapę

Możesz najpierw utworzyć rozmiar potrzebnej tablicy, wypełnić ją niezdefiniowaną, a następnie utworzyć nową tablicę za pomocą map, która ustawia każdy element na indeks.

var foo = Array(N).fill().map((v,i)=>i);

Array.from

Powinno to być inicjowanie do długości rozmiaru N i zapełnianie tablicy w jednym przebiegu.

Array.from({ length: N }, (v, i) => i)



Zamiast komentarzy i zamieszania, jeśli naprawdę chcesz uchwycić wartości z 1..N w powyższych przykładach, istnieje kilka opcji:

  1. jeśli indeks jest dostępny, możesz po prostu zwiększyć go o jeden (np ++i.).
  2. w przypadkach, gdy indeks nie jest używany - i być może bardziej wydajnym sposobem - jest utworzenie tablicy, ale ustawienie N oznacza N + 1, a następnie przesunięcie z przodu.

    Więc jeśli chcesz 100 liczb:

    let arr; (arr=[ ...Array(101).keys() ]).shift()





Uważam, że jest to przydatne, gdy tablica liczb jest używana dla danych, których nie można przetworzyć na końcu odbierającym. (Jak szablon HTML, który właśnie zastępuje wartości.)
Neil Monroe

Dlaczego ktoś miałby to zrobić, to mieć tablicę liczb, aby wypełnić listę rozwijaną, dając użytkownikowi wybór od 1 do 10. Mała tablica ręcznie [1,2,3 ... 10] ma sens, ale co jeśli to od 1 do 50? Co się stanie, jeśli zmieni się numer końcowy?
CigarDoug

@CigarDoug Nie wątpię, że istnieje przypadek użycia, ale sądzę, że jest mały. Dlaczego miałaby być potrzebna tablica liczb, zwykle podczas iteracji po tablicy indeks byłby używany jako część konstrukcji pętli - albo jako argument funkcji zapętlającej funkcji ciała, albo jako zmienna przeciwna - więc trzymanie tablicy liczb wydaje się trywialne po prostu tworząc tablicę o określonej szerokości lub po prostu zmienną, która utrzymuje górną granicę tablicy. Mogę wymyślić kilka przypadków użycia, ale żaden z nich nie został wyrażony przez OP
vol7ron

4
Tak jak powiedziałem, muszę wypełnić listę cyframi od 1 do 10. To wszystko. Jest skrzynka, MOJA skrzynka. Tak znalazłem tę stronę. Więc zbudowanie tablicy ręcznie było mniej skomplikowane niż cokolwiek, co tu widziałem. Więc moje wymagania nie są wymaganiami PO. Ale mam odpowiedź.
CigarDoug

1
@ vol7ron Jest przypadek użycia, ja też go mam. Angular, stronicowanie, chcę pokazać strony w stopce, które można kliknąć. Pętlę więc elementy w widoku za pomocą * ngFor = "let p of PagesCounter". Masz na to lepsze rozwiązanie? BTW, sprawdź stackoverflow.com/questions/36354325/…
Dalibor

186

W ES6 możesz wykonać:

Array(N).fill().map((e,i)=>i+1);

http://jsbin.com/molabiluwa/edit?js,console

Edycja: Zmieniono Array(45)na Array(N)od czasu zaktualizowania pytania.

console.log(
  Array(45).fill(0).map((e,i)=>i+1)
);


3
+1, ponieważ jest o całe duże O lepsze niż nieprzyjemna .join.splitwersja - ale nadal uważam, że skromna pętla jest lepsza.
Robin

Zgadzam się @Robin - pomijając złożoność algorytmiczną, skromna pętla jest zawsze bardziej czytelna. Jednak wraz z pojawieniem się lambdas w Javie, myślę, że mapwkrótce stanie się standardem dla takich rzeczy.
Nate

4
const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]
Robin

8
Nie rozumiem, dlaczego .fill()jest to konieczne. Widzę, że Array(1)[0] === undefineddzieje się tak, kiedy testuję replikę węzła, ale od jakiej różnicy robi się wywołanie fill () Array(1).fill(undefined)?
Dominic

11
Dla każdego, kto jest zainteresowany, dobrze wyjaśniono różnicę między Array (N) a Array (N) .fill () tutaj
Dominic

108

Użyj bardzo popularnej metody podkreślenia _.range

// _.range([start], stop, [step])

_.range(10); // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_.range(1, 11); // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
_.range(0, 30, 5); // => [0, 5, 10, 15, 20, 25]
_.range(0, -10, -1); //  => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
_.range(0); // => []


Niesamowite. Pokaż mi duży projekt, który i tak nie używa podkreślenia ...
Erez Cohen

63
function range(start, end) {
    var foo = [];
    for (var i = start; i <= end; i++) {
        foo.push(i);
    }
    return foo;
}

Następnie zadzwonił

var foo = range(1, 5);

Nie ma wbudowanego sposobu, aby to zrobić w JavaScript, ale jest to całkowicie poprawna funkcja narzędzia, którą można utworzyć, jeśli musisz to zrobić więcej niż raz.

Edycja: Moim zdaniem, lepsza funkcja zakresu jest następująca. Może po prostu dlatego, że jestem stronniczy przez LINQ, ale myślę, że jest to bardziej przydatne w większej liczbie przypadków. Twój przebieg może się różnić.

function range(start, count) {
    if(arguments.length == 1) {
        count = start;
        start = 0;
    }

    var foo = [];
    for (var i = 0; i < count; i++) {
        foo.push(start + i);
    }
    return foo;
}

2
Lubię to. Jeśli chcesz zrobić z nim więcej, możesz zadeklarować go jako Array.prototype.range = function (start, end) {...} ;. Następnie możesz wywołać zakres (x, y) na dowolnym obiekcie Array.
Zach Rattner,

8
Zamiast tego uczyń to metodą Arrayzamiast, Array.prototypeponieważ nie ma żadnego powodu (może to być nawet uważane za głupie), aby mieć tę metodę na każdej tablicy.
Adam

9
Array.range(1, 5)byłoby prawdopodobnie bardziej odpowiednie, ale w pisaniu jest coś fajnego [].range(1, 5).
MooGoo,

„Zamiast tego uczyń to metodą Array zamiast Array.prototype” - jaka jest różnica? Masz na myśli tylko określoną tablicę?
pilau

3
@pilau Tak jak mówi Adam, wygląda dziwnie. Jeśli jest na prototypie, możesz powiedzieć foo = [1, 2, 3]; bar = foo.range(0, 10);. Ale to po prostu ... mylące. bar = Array.range(0, 10)jest o wiele bardziej jasne i wyraźne. Zakres nie ma nic wspólnego z instancją, więc nie ma powodu, aby uczynić ją metodą instancji.
Ian Henry

53

najszybszym sposobem na wypełnienie Arrayv8 jest:

[...Array(5)].map((_,i) => i);

wynikiem będzie: [0, 1, 2, 3, 4]


czy można to zrobić bez dodatkowej zmiennej _
bluejayke

@bluejayke no :(
аlex dykyі

harsh, czy wiesz, jaki jest kod źródłowy .map? Nie jestem pewien, czy jest to szybsze niż pętla for, ale jeśli nie, teoretycznie możemy po prostu zdefiniować Właściwość i zrobić nową
bluejayke

49

To pytanie ma wiele skomplikowanych odpowiedzi, ale prosty jednoliniowy:

[...Array(255).keys()].map(x => x + 1)

Ponadto, chociaż powyższe jest krótkie (i schludne) do napisania, myślę, że następujące jest nieco szybsze (dla maksymalnej długości:

127, Int8,

255, Uint8,

32 767, Int16,

65 535, Uint16,

2 147 483 647, Int32,

4 294 967 295, Uint32.

(w oparciu o maksymalne wartości całkowite ), oto także więcej o tablicach typowanych ):

(new Uint8Array(255)).map(($,i) => i + 1);

Chociaż to rozwiązanie również nie jest takie idealne, ponieważ tworzy dwie tablice i używa dodatkowej zmiennej deklaracji „$” (nie jestem pewien, jak to obejść za pomocą tej metody). Myślę, że następujące rozwiązanie jest absolutnie najszybszym możliwym sposobem na to:

for(var i = 0, arr = new Uint8Array(255); i < arr.length; i++) arr[i] = i + 1;

W dowolnym momencie po wykonaniu tej instrukcji można po prostu użyć zmiennej „arr” w bieżącym zakresie;

Jeśli chcesz zrobić z niego prostą funkcję (z pewną podstawową weryfikacją):

function range(min, max) {
    min = min && min.constructor == Number ? min : 0;
    !(max && max.constructor == Number && max > min) && // boolean statements can also be used with void return types, like a one-line if statement.
        ((max = min) & (min = 0));  //if there is a "max" argument specified, then first check if its a number and if its graeter than min: if so, stay the same; if not, then consider it as if there is no "max" in the first place, and "max" becomes "min" (and min becomes 0 by default)

    for(var i = 0, arr = new (
        max < 128 ? Int8Array : 
        max < 256 ? Uint8Array :
        max < 32768 ? Int16Array : 
        max < 65536 ? Uint16Array :
        max < 2147483648 ? Int32Array :
        max < 4294967296 ? Uint32Array : 
        Array
    )(max - min); i < arr.length; i++) arr[i] = i + min;
    return arr;
}



//and you can loop through it easily using array methods if you want
range(1,11).forEach(x => console.log(x));

//or if you're used to pythons `for...in` you can do a similar thing with `for...of` if you want the individual values:
for(i of range(2020,2025)) console.log(i);

//or if you really want to use `for..in`, you can, but then you will only be accessing the keys:

for(k in range(25,30)) console.log(k);

console.log(
    range(1,128).constructor.name,
    range(200).constructor.name,
    range(400,900).constructor.name,
    range(33333).constructor.name,
    range(823, 100000).constructor.name,
    range(10,4) // when the "min" argument is greater than the "max", then it just considers it as if there is no "max", and the new max becomes "min", and "min" becomes 0, as if "max" was never even written
);


dzięki powyższej funkcji powyższy superpowolny „prosty jeden linijka” staje się superszybki, a nawet krótszy:

range(1,14000);

@JVG, ale nie dla szybszej funkcji?
bluejayke

Dokładnie tak. To ta prosta wkładka, której wszyscy szukają!
supersan,

@ supersan chociaż jest super wolny :)
bluejayke

Nowoczesny javascript z nową fillmetodą:Array(255).fill(0,0,255)
cacoder

@cacoder jak szybko to jest, ile tablic tworzy i ile iteracji?
bluejayke

42

Możesz użyć tego:

new Array(/*any number which you want*/)
    .join().split(',')
    .map(function(item, index){ return ++index;})

na przykład

new Array(10)
    .join().split(',')
    .map(function(item, index){ return ++index;})

utworzy następującą tablicę:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

A czemu nie new Array(10).join().split(',').map(function() {return ++arguments[1]});?
super

1
@Murplyx niektórych przypadkach działać z argumentów wewnątrz nie będą zoptymalizowane przez silnik JS (nawet dla V8, patrz jsperf.com/arguments-vs-array-argument/2 )
nktssh

4
Jest to interesujące rozwiązanie, ale jest całkowicie niepraktyczne - konieczność parsowania tablicy 3 razy (raz do join, raz do spliti raz dla rzeczy, którą naprawdę chcesz zrobić) po prostu nie jest fajna - wiem, że wydaje się, że wypadły one z łask z jakiegoś powodu, ale o wiele lepiej byłoby po prostu użyć starej, dobrej klasy pętli !
Robin

42

ES6 to załatwi sprawę:

[...Array(12).keys()]

sprawdź wynik:

[...Array(12).keys()].map(number => console.log(number))


5
właściwie poprosili o 1..N, a nie 0..N-1
JakowL

1
tak, [...Array(N + 1).keys()].slice(1)przyniesie 1..N
David G

Z jakiegoś powodu to rozwiązanie nie działa w wersji produkcyjnej z aplikacji Expo (reagująca natywnie). [...Array(N + 1).keys()]ten kod zwraca pustą tablicę, ale tylko w trybie produkcyjnym, przy użyciu trybu programowania działa.
FabianoLothor

3
.keys()Odpowiedź została już podana lat temu i ma ponad 500 upvotes. Co do tego dodaje twoja odpowiedź?
Dan Dascalescu,

39

Jeśli akurat używasz d3.js w swojej aplikacji, tak jak ja, D3 zapewnia funkcję pomocniczą, która robi to za Ciebie.

Aby uzyskać tablicę od 0 do 4, jest to tak proste jak:

d3.range(5)
[0, 1, 2, 3, 4]

i uzyskać tablicę od 1 do 5, tak jak prosiłeś:

d3.range(1, 5+1)
[1, 2, 3, 4, 5]

Sprawdź ten samouczek, aby uzyskać więcej informacji.


Ten komentarz podsunął mi pomysł, aby sprawdzić funkcję range () w RamdaJS, która jest biblioteką JS, nad którą pracuję nad moim bieżącym projektem. Doskonały.
morfatyczny


38

Jest to prawdopodobnie najszybszy sposób na wygenerowanie tablicy liczb

Najkrótszy

var a=[],b=N;while(b--)a[b]=b+1;

Inline

var arr=(function(a,b){while(a--)b[a]=a;return b})(10,[]);
//arr=[0,1,2,3,4,5,6,7,8,9]

Jeśli chcesz zacząć od 1

var arr=(function(a,b){while(a--)b[a]=a+1;return b})(10,[]);
//arr=[1,2,3,4,5,6,7,8,9,10]

Chcesz funkcję?

function range(a,b,c){c=[];while(a--)c[a]=a+b;return c}; //length,start,placeholder
var arr=range(10,5);
//arr=[5,6,7,8,9,10,11,12,13,14]

DLACZEGO?

  1. while jest najszybszą pętlą

  2. Ustawienie bezpośrednie jest szybsze niż push

  3. [] jest szybszy niż new Array(10)

  4. jest krótki ... spójrz na pierwszy kod. następnie spójrz na wszystkie inne funkcje tutaj.

Jeśli podoba Ci nie może żyć bez za

for(var a=[],b=7;b>0;a[--b]=b+1); //a=[1,2,3,4,5,6,7]

lub

for(var a=[],b=7;b--;a[b]=b+1); //a=[1,2,3,4,5,6,7]

8
Lepiej byłoby poprzeć te twierdzenia wzorcami. Spróbuj jsperf.com .
Matt Ball

2
lol jsperf ... pls Matt, tylko że nie podoba ci się moja odpowiedź przestań głosować na moich innych ... stackoverflow.com/a/18344296/2450730 ... użyj console.time () lub jak to się nazywa ... NIE jsperf .
cocco

4
FYI: Jak John Reisig po raz pierwszy opublikował kilka lat temu - na niektórych platformach (czyli Windows: P) czas jest przesyłany do przeglądarki raz na 16ms. Istnieją również inne problemy z pomiarem czasu wykonania w środowiskach wielozadaniowych. jsperf.com zaimplementował uruchamianie testów, aby były one statystycznie poprawne. Można uruchomić, console.time()aby uzyskać intuicję, ale na dowód potrzebujesz jsperf.com ORAZ pokazuje ona wyniki innych przeglądarek od innych osób (inny sprzęt itp.)
naugtur 14.09.2013

3
@cocco jest to nieprawidłowe:var a=[],b=N;while(b--){a[b]=a+1};
vintagexav

5
@ cocco - podczas gdy nie zawsze jest szybszy niż inne pętle. W niektórych przeglądarkach dekrementacja podczas gdy pętla jest znacznie wolniejsza niż w przypadku pętli for, nie można wydawać ogólnych oświadczeń dotyczących wydajności javascript, ponieważ istnieje tak wiele implementacji z tak wieloma różnymi optymalizacjami. Jednak ogólnie podoba mi się twoje podejście. ;-)
RobG

32

nowy sposób napełniania Arrayto:

const array = [...Array(5).keys()]
console.log(array)

wynikiem będzie: [0, 1, 2, 3, 4]


To naprawdę dobra odpowiedź, choć technicznie pytanie brzmiało od 1-N, a nie 0- (N-1)
bluejayke

31

Jeśli używasz lodash, możesz użyć _.range :

_.range([start=0], end, [step=1])

Tworzy tablicę liczb (dodatnich i / lub ujemnych), które zaczynają się od początku do końca, ale nie obejmują. Krok -1 jest używany, jeśli określono ujemny początek bez końca lub kroku. Jeśli nie określono końca, ustawi się na początek, a następnie na 0.

Przykłady:

_.range(4);
// ➜ [0, 1, 2, 3]

_.range(-4);
// ➜ [0, -1, -2, -3]

_.range(1, 5);
// ➜ [1, 2, 3, 4]

_.range(0, 20, 5);
// ➜ [0, 5, 10, 15]

_.range(0, -4, -1);
// ➜ [0, -1, -2, -3]

_.range(1, 4, 0);
// ➜ [1, 1, 1]

_.range(0);
// ➜ []

30

z ES6 możesz wykonać:

// `n` is the size you want to initialize your array
// `null` is what the array will be filled with (can be any other value)
Array(n).fill(null)

Ponieważ wartości tablicy są wypełniane przy użyciu tego rozwiązania mapi forEachbędą działać.
dontmention thebackup

26

Końcowy raport podsumowujący. Drrruummm Rolll -

Jest to najkrótszy kod do wygenerowania tablicy o rozmiarze N (tutaj 10) bez użycia ES6 . Powyższa wersja Cocco jest bliska, ale nie najkrótsza.

(function(n){for(a=[];n--;a[n]=n+1);return a})(10)

Ale niekwestionowanym zwycięzcą tego golfa Code (rywalizacja o rozwiązanie konkretnego problemu w najmniejszej liczbie bajtów kodu źródłowego) jest Niko Ruotsalainen . Korzystanie z Array Constructor i operatora rozprzestrzeniania ES6 . (Większość składni ES6 jest poprawnym typem skryptu, ale nie jest to zgodne z poniższym. Więc bądź rozsądny podczas korzystania z niego)

[...Array(10).keys()]

Dlaczego głosować w dół? Długa lista odpowiedzi trudna do naśladowania, więc pomyślałem o podsumowaniu.
sapy

czy to nie 0-10? [... Array (10) .keys ()]
Greg

Webstorm sugeruje (nowy Array (10)). Keys (), czy to prawda?
Guy

(new Array (10)). keys (), zwraca ArrayIterator {}, a nie tablicę
sapy

To tworzy zmienną globalną a. Pętla powinna byćfor(var a=[];n--;a[n]=n+1)
kube

20

Jest jeszcze inny sposób w ES6, używając Array.from, który pobiera 2 argumenty, pierwszy to tablicaLike (w tym przypadku obiekt z lengthwłaściwością), a druga to funkcja mapowania (w tym przypadku mapujemy element na jego indeks)

Array.from({length:10}, (v,i) => i)

jest to krótsze i może być wykorzystane do innych sekwencji, takich jak generowanie liczb parzystych

Array.from({length:10}, (v,i) => i*2)

Ma to również lepszą wydajność niż większość innych sposobów, ponieważ zapętla się tylko raz przez tablicę. Sprawdź snippit dla niektórych porównań

// open the dev console to see results

count = 100000

console.time("from object")
for (let i = 0; i<count; i++) {
  range = Array.from({length:10}, (v,i) => i )
}
console.timeEnd("from object")

console.time("from keys")
for (let i =0; i<count; i++) {
  range = Array.from(Array(10).keys())
}
console.timeEnd("from keys")

console.time("apply")
for (let i = 0; i<count; i++) {
  range = Array.apply(null, { length: 10 }).map(function(element, index) { return index; })
}
console.timeEnd("apply")


Hej, to miłe, podoba mi się. Jednak nie zwraca wyników, których oczekuje OP. Aby to zrobić, należy zapisać jakoArray.from({length:N}, (v,i) => i+1)
CervEd,


16

Używanie nowych metod Array i =>składni funkcji ze standardu ES6 (tylko Firefox w momencie pisania).

Wypełniając otwory undefined:

Array(N).fill().map((_, i) => i + 1);

Array.fromzwojów „dziury” w undefinedtak Array.mapdziała zgodnie z oczekiwaniami:

Array.from(Array(5)).map((_, i) => i + 1)

7
Podobnie, można również wykonać następujące czynności w ES6: Array.from({length: N}, (v, k) => k).
XåpplI'-I0llwlg'I -

Preferowane jest podejście Xappli: Array.from został stworzony dla prawie tego dokładnie scenariusza i implikuje wywołanie zwrotne mapowania. Jest to doskonałe rozwiązanie ogólnego problemu z chęcią użycia metod Array na czymś podobnym do tablicy, bez uciekania się do pełnych podejść, takich jak Array.prototype.map.callnp. Dla NodeLists, z których powrócono document.querySelectorAll. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Josh z Qaribou

Ważę to w porównaniu ze składnią zakresu podkreślenia, a zakres czyta się lepiej.
ooolala,

Technicznie rzecz biorąc, to nie Array.fromzmienia rzadkie wartości w niezdefiniowane. Jest raczej Array(5)wywoływany jako obiekt argumentów, który z kolei interpretuje wartości rzadkie jako wartości niezdefiniowane :)
CervEd



11

W ES6:

Array.from({length: 1000}, (_, i) => i);

ES5:

Array.apply(0, {length: 1000}).map(function(x,i){return i});

10

Po prostu kolejna wersja ES6 .

Korzystając z Array.fromdrugiego opcjonalnego argumentu:

Array.from (arrayLike [, mapFn [, thisArg]])

Możemy zbudować tablicę numeryczną z pustych Array(10)pozycji:

Array.from(Array(10), (_, i) => i)

var arr = Array.from(Array(10), (_, i) => i);
document.write(arr);


Jest to bardziej skomplikowane i ~ 10 razy wolniejsze niż [...Array(11).keys()].slice(1).
Dan Dascalescu,

10

Wydaje się, że jedynym smakiem, którego obecnie nie ma na tej dość kompletnej liście odpowiedzi, jest generator z generatorem; aby temu zaradzić:

const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]

które można wykorzystać w ten sposób:

gen(4) // [0,1,2,3]

Zaletą tego jest to, że nie musisz tylko zwiększać ... Aby czerpać inspirację z odpowiedzi udzielonej przez @ igor-shubin, możesz bardzo łatwo stworzyć szereg losowości:

const gen = N => [...(function*(){let i=0;
  while(i++<N) yield Math.random()
})()]

I zamiast czegoś długiego kosztowo operacyjnego, takiego jak:

const slow = N => new Array(N).join().split(',').map((e,i)=>i*5)
// [0,5,10,15,...]

zamiast tego możesz:

const fast = N => [...(function*(){let i=0;while(i++<N)yield i*5})()]

10

Możesz użyć wypełnienia macierzy i mapy z Es6; tak jak kilka osób sugerowało w odpowiedziach na to pytanie. Poniżej kilka przykładów:

Example-One: Array(10).fill(0).map((e,i)=>i+1)

Result-One: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Example-Two: Array(100/10).fill(0).map((e,i)=>(i*10)+10)

Result-Two:[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

Wolę to, ponieważ uważam to za proste i łatwiejsze.



9

Korzystanie z ES6

const generateArray = n => [...Array(n)].map((_, index) => index + 1);

Dzięki! To była moim zdaniem najbardziej elegancka odpowiedź! Można również użyć, Array.from(Array(n))jeśli operator rozkładania nie jest obsługiwany.
Amit,

Na początku nie wiedziałem, dlaczego musiałeś użyć operatora rozkładania, ale potem przeczytałem o mapMDN : „Nie jest wywoływane z powodu brakujących elementów tablicy (czyli indeksów, które nigdy nie były ustawione, które miały zostały usunięte lub którym nigdy nie przypisano wartości). ”
battmanz

9

Object.keys(Array.apply(0, Array(3))).map(Number)

Powraca [0, 1, 2]. Bardzo podobny do doskonałej odpowiedzi Igora Shubina , ale z nieco mniej sztuczką (i jedną postacią dłuższą).

Wyjaśnienie:

  • Array(3) // [undefined × 3]Wygeneruj tablicę o długości n = 3. Niestety ta tablica jest dla nas prawie bezużyteczna, dlatego musimy…
  • Array.apply(0,Array(3)) // [undefined, undefined, undefined]uczyń tablicę iterowalną. Uwaga: null jest bardziej powszechny jako pierwszy argument Apply, ale 0 jest krótszy.
  • Object.keys(Array.apply(0,Array(3))) // ['0', '1', '2'] następnie zdobądź klucze tablicy (działa, ponieważ tablice są typem tablica to obiekt z indeksami dla kluczy.
  • Object.keys(Array.apply(0,Array(3))).map(Number) // [0, 1, 2] i mapuj klawisze, konwertując ciągi na liczby.
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.