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.

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

scunliffe
źródło
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]
Niko Ruotsalainen
źródło
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.

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

Abdennour TOUMI
źródło
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()




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

Nate
źródło
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); // => []
Evan
źródło
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;
}
Ian Henry
źródło
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]

Alex dykyі
źródło
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);
bluejayke
źródło
@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]
nktssh
źródło
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))

chrześcijanin
źródło
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.

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

Za pomocą operatora rozprzestrzeniania ES2015 / ES6

[...Array(10)].map((_, i) => i + 1)

console.log([...Array(10)].map((_, i) => i + 1))

Vlad Bezden
źródło
7
i + 1miałoby więcej sensu niż ++i.
Vincent Cantin
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]
cocco
źródło
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]

Alex dykyі
źródło
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);
// ➜ []
Hongbo Miao
źródło
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)

źródło
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()]
sapy
źródło
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")

gafi
źródło
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,
Te hacki neato są nadal 5-10 razy wolniejsze niż dobre stare pętle for .
Dan Dascalescu,
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)
szymzet
źródło
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
15

Array(...Array(9)).map((_, i) => i);

console.log(Array(...Array(9)).map((_, i) => i))

Alex dykyі
źródło
Miły! Może również napisać to bardziej zwięźle, ponieważ[...Array(9)].map((_, i) => i)
Eamonn O'Brien-Strain
13
for(var i,a=[i=0];i<10;a[i++]=i);

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

SammieFox
źródło
Naprawdę niesamowite! Tx!
Pedro Ferreira,
11

W ES6:

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

ES5:

Array.apply(0, {length: 1000}).map(function(x,i){return i});
bluejayke
źródło
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);

zurfyx
źródło
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})()]
Rudzik
źródło
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.

Gbemi Kadri
źródło
9

Korzystanie z ES6

const generateArray = n => [...Array(n)].map((_, index) => index + 1);
Geoffrey Abdallah
źródło
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.
mLuby
źródło