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.
javascript
arrays
Godders
źródło
źródło
1 ... N
?Odpowiedzi:
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?
wtedy, gdy chcesz go użyć ... (niezoptymalizowany, na przykład)
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/
źródło
var n = 45;
a następnie zapętlenie od1..n
.foo.length = M
--- Informacje o odcięciu zostaną utracone. Zobacz to w akcji ==> jsfiddle.net/ACMXpvar n = 45;
.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 jakvar foo = []; foo.length=45;
. DlategoforEach
imap
nie będzie miało zastosowania w tym przypadku.W ES6 przy użyciu metod Array from () i keys () .
Krótsza wersja z operatorem rozkładania .
źródło
map
z tablicą, aby dostosować wartości ([...Array(10).keys()].map(x => x++);
), aby zacząć od 1map(x => x++)
namap(x => ++x)
ze względu na przyrost pierwszeństwa po zwrocie wartości :)map
kiedy możesz po prostuslice
?[...Array(N+1).keys()].slice(1)
keys
i tylko 1 mapa ->Array.from(Array(10)).map((e,i)=>i+1)
from
Array.from(Array(10), (e,i)=>i+1)
Możesz to zrobić:
lub z losowymi wartościami:
Wyjaśnienie
Po pierwsze, zwróć uwagę na
Number.call(undefined, N)
toNumber(N)
, co po prostu zwracaN
. Wykorzystamy ten fakt później.Array.apply(null, [undefined, undefined, undefined])
jest równoważne zArray(undefined, undefined, undefined)
, który tworzy tablicę trzyelementową i przypisujeundefined
do 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:Od ECMAScript 5 ,
Function.prototype.apply(thisArg, argsArray)
przyjmuje również kaczki wpisany tablicowej obiekt jako drugi parametr. Jeśli wywołamyArray.apply(null, { length: N })
, to się uruchomiTeraz mamy tablicę N- element, z każdym elementem ustawionym na
undefined
. Kiedy.map(callback, thisArg)
go wywołamy, każdy element zostanie ustawiony na wynikcallback.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, jakNumber.call(undefined, index, array)
, jak zaobserwowaliśmy wcześniej, oceniaindex
. 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 prostuArray(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()
: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.źródło
Function.prototype.call
pierwszym parametrem jestthis
obiekt do mapowania bezpośrednio nadArray.prototype.map
parametrem iteratora, ma pewną błyskotliwość.map
Moim 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; })
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)
Wiele sposobów korzystania z ES6
Korzystanie z
...
metody spread operator ( ) i keysWypełnij / mapę
Array.from
Array. From and
{ length: N }
hackUwaga na temat formy uogólnionej
Wszystkie powyższe formy tablic może produkować zerowana do prawie każdej żądanej wartości poprzez zmianę
i+1
ekspresji wymagane (npi*2
,-i
,1+i*2
,i%2
i etc). Jeśli wyrażenie może być wyrażone przez jakąś funkcję,f
wówczas pierwsza forma staje się po prostuPrzykłady:
Ponieważ tablica jest inicjowana
undefined
dla każdej pozycji, wartościąv
będzieundefined
Przykład przedstawiający wszystkie formularze
Pokaż fragment kodu
Bardziej ogólny przykład z niestandardową funkcją inicjalizacji,
f
tjlub nawet prościej
Pokaż fragment kodu
źródło
k++
, używaj++k
.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,
indexOf
można zastosować tę metodę.To powiedziawszy, dla twoich potrzeb możesz po prostu zadeklarować tablicę o określonym rozmiarze:
ES6
Rozpowszechnianie się
Korzystanie z operatora spread (
...
) ikeys
metody 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: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.Array.from
Powinno to być inicjowanie do długości rozmiaru N i zapełnianie tablicy w jednym przebiegu.
Zamiast komentarzy i zamieszania, jeśli naprawdę chcesz uchwycić wartości z 1..N w powyższych przykładach, istnieje kilka opcji:
++i
.).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:
źródło
W ES6 możesz wykonać:
Array(N).fill().map((e,i)=>i+1);
http://jsbin.com/molabiluwa/edit?js,console
Edycja: Zmieniono
Array(45)
naArray(N)
od czasu zaktualizowania pytania.źródło
.join.split
wersja - ale nadal uważam, że skromna pętla jest lepsza.map
wkrótce stanie się standardem dla takich rzeczy.const gen = N => [...(function*(){let i=0;while(i<N)yield i++})()]
.fill()
jest to konieczne. Widzę, żeArray(1)[0] === undefined
dzieje się tak, kiedy testuję replikę węzła, ale od jakiej różnicy robi się wywołanie fill ()Array(1).fill(undefined)
?Użyj bardzo popularnej metody podkreślenia _.range
źródło
Następnie zadzwonił
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ć.
źródło
Array
zamiast,Array.prototype
ponieważ nie ma żadnego powodu (może to być nawet uważane za głupie), aby mieć tę metodę na każdej tablicy.Array.range(1, 5)
byłoby prawdopodobnie bardziej odpowiednie, ale w pisaniu jest coś fajnego[].range(1, 5)
.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.najszybszym sposobem na wypełnienie
Array
v8 jest:wynikiem będzie:
[0, 1, 2, 3, 4]
źródło
To pytanie ma wiele skomplikowanych odpowiedzi, ale prosty jednoliniowy:
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 ):
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:
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ą):
dzięki powyższej funkcji powyższy superpowolny „prosty jeden linijka” staje się superszybki, a nawet krótszy:
źródło
fill
metodą:Array(255).fill(0,0,255)
Możesz użyć tego:
na przykład
utworzy następującą tablicę:
źródło
new Array(10).join().split(',').map(function() {return ++arguments[1]});
?join
, raz dosplit
i 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 !ES6 to załatwi sprawę:
sprawdź wynik:
źródło
[...Array(N + 1).keys()].slice(1)
przyniesie 1..N[...Array(N + 1).keys()]
ten kod zwraca pustą tablicę, ale tylko w trybie produkcyjnym, przy użyciu trybu programowania działa..keys()
Odpowiedź została już podana lat temu i ma ponad 500 upvotes. Co do tego dodaje twoja odpowiedź?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:
i uzyskać tablicę od 1 do 5, tak jak prosiłeś:
Sprawdź ten samouczek, aby uzyskać więcej informacji.
źródło
Za pomocą operatora rozprzestrzeniania ES2015 / ES6
źródło
i + 1
miałoby więcej sensu niż++i
.Jest to prawdopodobnie najszybszy sposób na wygenerowanie tablicy liczb
Najkrótszy
Inline
Jeśli chcesz zacząć od 1
Chcesz funkcję?
DLACZEGO?
while
jest najszybszą pętląUstawienie bezpośrednie jest szybsze niż
push
[]
jest szybszy niżnew Array(10)
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
lub
źródło
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.)var a=[],b=N;while(b--){a[b]=a+1};
nowy sposób napełniania
Array
to:wynikiem będzie:
[0, 1, 2, 3, 4]
źródło
Jeśli używasz lodash, możesz użyć _.range :
Przykłady:
źródło
z ES6 możesz wykonać:
źródło
map
iforEach
będą działać.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.
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)
źródło
a
. Pętla powinna byćfor(var a=[];n--;a[n]=n+1)
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
length
właściwością), a druga to funkcja mapowania (w tym przypadku mapujemy element na jego indeks)jest to krótsze i może być wykorzystane do innych sekwencji, takich jak generowanie liczb parzystych
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ń
źródło
Array.from({length:N}, (v,i) => i+1)
Używanie nowych metod Array i
=>
składni funkcji ze standardu ES6 (tylko Firefox w momencie pisania).Wypełniając otwory
undefined
:Array.from
zwojów „dziury” wundefined
takArray.map
działa zgodnie z oczekiwaniami:źródło
Array.from({length: N}, (v, k) => k)
.Array.prototype.map.call
np. Dla NodeLists, z których powróconodocument.querySelectorAll
. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…Array.from
zmienia rzadkie wartości w niezdefiniowane. Jest raczejArray(5)
wywoływany jako obiekt argumentów, który z kolei interpretuje wartości rzadkie jako wartości niezdefiniowane :)źródło
[...Array(9)].map((_, i) => i)
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
źródło
W ES6:
ES5:
źródło
Po prostu kolejna wersja ES6 .
Korzystając z
Array.from
drugiego opcjonalnego argumentu:Możemy zbudować tablicę numeryczną z pustych
Array(10)
pozycji:źródło
[...Array(11).keys()].slice(1)
.Wydaje się, że jedynym smakiem, którego obecnie nie ma na tej dość kompletnej liście odpowiedzi, jest generator z generatorem; aby temu zaradzić:
które można wykorzystać w ten sposób:
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:
I zamiast czegoś
długiego kosztowooperacyjnego, takiego jak:zamiast tego możesz:
źródło
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:
Wolę to, ponieważ uważam to za proste i łatwiejsze.
źródło
Źródło: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from
źródło
Korzystanie z ES6
źródło
Array.from(Array(n))
jeśli operator rozkładania nie jest obsługiwany.map
MDN : „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). ”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.źródło