Jaki jest najskuteczniejszy sposób na utworzenie dowolnej liczby pól wypełnionych zerami w JavaScript?
javascript
arrays
dil
źródło
źródło
let i = 0; Array.from(Array(10), ()=>i++);
Odpowiedzi:
ES6 wprowadza
Array.prototype.fill
. Można go użyć w następujący sposób:Nie jestem pewien, czy jest szybki, ale podoba mi się, ponieważ jest krótki i samoopisujący się.
Nadal nie ma go w IE ( sprawdź kompatybilność ), ale dostępny jest polypełniacz .
źródło
new Array(len)
jest boleśnie powolny.(arr = []).length = len; arr.fill(0);
dotyczy najszybszego rozwiązania, jakie kiedykolwiek widziałem ... lub przynajmniej wiążearr = Array(n)
i(arr = []).length = n
zachowuj się identycznie zgodnie ze specyfikacją. W niektórych implementacjach może być szybsze, ale nie sądzę, że jest duża różnica.(arr = []).length = 1000;
przedarr = new Array(1000);
testem prędkości je zarówno w Chrome i FF na ...new
jest strasznie powolny. Teraz, dla tablic o mniejszej długości ... powiedzmy <50 lub mniej więcej ... wtedynew Array()
wydaje się, że działa lepiej. Ale ..arr.fill(0)
... wszystko się zmienia. Teraz użycienew Array()
jest szybsze w większości przypadków, z wyjątkiem sytuacji, gdy dojdziesz do rozmiarów tablic> 100000 ... Wtedy możesz zacząć widzieć, jak ponownie rośnie szybkość. Ale jeśli tak naprawdę nie musisz wypełniać go zerami i możesz użyć standardowej fali pustych tablic. W(arr = []).length = x
moich testowych przypadkach przez większość czasu jest szalony szybko.new Array(5).forEach(val => console.log('hi'));
kontranew Array(5).fill(undefined).forEach(val => console.log('hi'));
.Chociaż jest to stary wątek, chciałem dodać do niego moje 2 centy. Nie jestem pewien, jak wolno / szybko to jest, ale jest to szybki jeden linijka. Oto co robię:
Jeśli chcę wstępnie wypełnić liczbą:
Jeśli chcę wstępnie wypełnić ciąg:
Inne odpowiedzi sugerują:
ale jeśli chcesz 0 (liczbę), a nie „0” (zero w ciągu), możesz:
źródło
Array.apply(null, new Array(5)).map(...)
? Bo po prostu robienie (nowa tablica (5)). Mapa (...) nie będzie działać, jak mówi specyfikacjanew
). Kiedy to robiszArray(5)
, tworzysz obiekt, który wygląda tak:{ length: 5, __proto__: Array.prototype }
- spróbujconsole.dir( Array(5) )
. Zauważ, że nie ma żadnych właściwości0
,1
,2
, itd. Ale kiedyapply
to aż doArray
konstruktora, to jak mówiąArray(undefined, undefined, undefined, undefined, undefined)
. I dostajesz przedmiot, który wygląda trochę{ length: 5, 0: undefined, 1: undefined...}
.map
Działa na właściwości0
,1
itp, dlatego Twój przykład nie działa, ale podczas korzystaniaapply
robi..apply
jest właściwie to, czym chceszthis
być. Dla tych celówthis
nie ma to znaczenia - zależy nam tylko na rozszerzeniu parametru „cechy”.apply
- więc może to być dowolna wartość. Podoba mi się,null
ponieważ jest tani, prawdopodobnie nie chcesz go używać{}
lub[]
ponieważ tworzysz obiekt bez powodu.Elegancki sposób na wypełnienie tablicy wstępnie obliczonymi wartościami
Oto inny sposób, aby to zrobić za pomocą ES6, o którym nikt dotąd nie wspominał:
Działa, przekazując funkcję mapy jako drugi parametr parametru
Array.from
.W powyższym przykładzie pierwszy parametr przydziela tablicę 3 pozycji wypełnionych wartością,
undefined
a następnie funkcja lambda odwzorowuje każdą z nich na wartość0
.Chociaż
Array(len).fill(0)
jest krótszy, nie działa, jeśli musisz najpierw wypełnić tablicę, wykonując obliczenia (wiem, że pytanie nie wymagało tego, ale wiele osób kończy tutaj, szukając tego) .Na przykład, jeśli potrzebujesz tablicy z 10 liczbami losowymi:
Jest bardziej zwięzły (i elegancki) niż odpowiednik:
Tej metody można również użyć do wygenerowania sekwencji liczb, korzystając z parametru indeksu podanego w wywołaniu zwrotnym:
Dodatkowa odpowiedź: wypełnij tablicę używając String
repeat()
Ponieważ ta odpowiedź cieszy się dużym zainteresowaniem, chciałem też pokazać tę fajną sztuczkę. Chociaż nie tak przydatna jak moja główna odpowiedź, wprowadzę wciąż mało znaną, ale bardzo przydatną
repeat()
metodę String . Oto sztuczka:Fajne hę?
repeat()
to bardzo przydatna metoda tworzenia ciągu znaków, który jest powtórzeniem ciągu oryginalnego kilka razy. Następniesplit()
tworzy dla nas tablicę, która następniemap()
dostosowuje się do pożądanych wartości. Podział na etapy:źródło
repeat
sztuczka zdecydowanie nie jest pożądana w produkcji,Array.from()
jest całkowicie w porządku :-)W skrócie
Najszybsze rozwiązanie
let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;
Najkrótsze (przydatne) rozwiązanie (3x wolniejsze dla małych tablic, nieco wolniejsze dla dużych (najwolniejsze w Firefox))
Array(n).fill(0)
Detale
Dzisiaj 2020.06.09 Przeprowadzam testy na macOS High Sierra 10.13.6 w przeglądarkach Chrome 83.0, Firefox 77.0 i Safari 13.1. Testuję wybrane rozwiązania dla dwóch przypadków testowych
Wnioski
new Array(n)+for
(N) jest najszybszym rozwiązaniem dla małych tablic i dużych tablic (oprócz Chrome, ale wciąż tam bardzo szybko) i jest zalecane jako szybkie rozwiązanie dla różnych przeglądareknew Float32Array(n)
(I) zwraca nietypową tablicę (np. nie można wywołać)push(..)
), więc nie porównuję jej wyników z innymi rozwiązaniami - jednak to rozwiązanie jest około 10-20 razy szybsze niż inne rozwiązania dla dużych tablic we wszystkich przeglądarkachfor
(L, M, N, O) są szybkie dla małych tablicfill
(B, C) są szybkie w Chrome i Safari, ale zaskakująco najwolniejsze w Firefox dla dużych tablic. Są średnio szybkie dla małych tablicArray.apply
(P) generuje błąd dla dużych tablicPokaż fragment kodu
Kod i przykład
Poniższy kod przedstawia rozwiązania stosowane w pomiarach
Pokaż fragment kodu
Przykładowe wyniki dla Chrome
źródło
let a=[]; for(i=n;i--;) a.push(0);
- ale jest 4x wolniejszy niżfill(0)
- więc nawet nie zaktualizuję obrazu z tą sprawą.a = new Array(n); for (let i = 0; i < n; ++i) a[i] = 0;
. TestWspomniana już metoda napełniania ES 6 ładnie się tym zajmuje. Większość współczesnych przeglądarek stacjonarnych obsługuje obecnie wymagane metody prototypów Array (Chromium, FF, Edge i Safari) [ 1 ]. Możesz sprawdzić szczegóły w MDN . Prostym przykładem użycia jest
Biorąc pod uwagę obecne wsparcie przeglądarki, powinieneś być ostrożny z jej użyciem, chyba że masz pewność, że Twoi odbiorcy korzystają z nowoczesnych przeglądarek Desktop.
źródło
a = Array(10).fill(null).map(() => { return []; });
a = Array(10).fill(0).map( _ => [] );
Uwaga dodana w sierpniu 2013 r., Zaktualizowana w lutym 2015 r .: Poniższa odpowiedź z 2009 r. Dotyczy ogólnego
Array
typu JavaScript . To nie dotyczy nowszych pisanych tablic zdefiniowanych w ES2015 [a teraz dostępne w wielu przeglądarkach], jakInt32Array
i takie. Należy również pamiętać, że ES2015 dodajefill
metodę zarówno do tablic, jak i tablic maszynowych , co może być najbardziej wydajnym sposobem ich wypełnienia ...Może to mieć duże znaczenie dla niektórych implementacji sposobu tworzenia tablicy. W szczególności silnik V8 Chrome próbuje użyć wysoce wydajnej, ciągłej tablicy pamięci, jeśli uważa, że jest to możliwe, przechodząc na tablicę obiektową tylko w razie potrzeby.
W większości języków byłoby to wstępnie alokować, a następnie wypełniać zerowo, jak poniżej:
Ale tablice JavaScript nie są tak naprawdę tablicami , są mapami klucz / wartość, tak jak wszystkie inne obiekty JavaScript, więc nie ma potrzeby „wstępnego przydzielania” (ustawienie długości nie przydziela tylu miejsc do wypełnienia), ani czy istnieje jakikolwiek powód, by sądzić, że korzyść z odliczenia do zera (co jest po prostu szybkie porównanie w pętli) nie jest ważniejsza przez dodanie kluczy w odwrotnej kolejności, gdy implementacja mogła zoptymalizować ich obsługę kluczy związane z tablicami teorii, generalnie wykonasz je w kolejności.
W rzeczywistości Matthew Crumley zwrócił uwagę, że odliczanie w Firefox jest znacznie wolniejsze niż liczenie w górę, co mogę potwierdzić - jest to jego część tablicowa (zapętlanie do zera jest wciąż szybsze niż zapętlenie do limitu w var). Najwyraźniej dodawanie elementów do tablicy w odwrotnej kolejności jest powolnym działaniem przeglądarki Firefox. W rzeczywistości wyniki różnią się nieco w zależności od implementacji JavaScript (co nie jest wcale takie zaskakujące). Oto szybka i brudna strona testowa (poniżej) dla implementacji przeglądarki (bardzo brudna, nie ustępuje podczas testów, więc zapewnia minimalną informację zwrotną i będzie działać z ograniczeniami czasowymi skryptów). Polecam odświeżenie między testami; FF (przynajmniej) spowalnia powtarzane testy, jeśli nie.
Dość skomplikowana wersja, która używa Array # concat, jest szybsza niż prosty init na FF, gdzieś pomiędzy 1000 a 2000 tablic elementów. Jednak w silniku V8 Chrome prosty init wygrywa za każdym razem ...
Oto strona testowa ( kopia na żywo ):
źródło
Domyślnie
Uint8Array
,Uint16Array
orazUint32Array
zajęcia zachować jej wartości jako zera, więc nie potrzeba żadnych skomplikowanych technik napełniania, po prostu zrobić:wszystkie elementy tablicy
ary
będą domyślnie zerami.źródło
Array.isArray(ary)
jestfalse
. Długość jest również tylko do odczytu, więc nie można wcisnąć do niej nowych elementów, jak w przypadkuary.push
0
jako domyślną wartość.Array.from(new Uint8Array(10))
zapewni normalną tablicę.Array(n).fill(0)
w Chrome, jeśli naprawdę potrzebujesz tablicy JS. Jeśli możesz użyć tablicy TypedArray, jest to o wiele szybsze nawet niż.fill(0)
, zwłaszcza jeśli możesz użyć domyślnej wartości inicjalizującej0
. Wydaje się, że nie ma konstruktora, który przyjmuje wartość wypełnienia i długość, tak jakstd::vector
ma to C ++ . Wydaje się, że dla każdej niezerowej wartości musisz zbudować wyzerowany TypedArray, a następnie go wypełnić. : /Jeśli używasz ES6, możesz użyć Array.from () w następujący sposób:
Ma taki sam wynik jak
Ponieważ
źródło
Należy pamiętać, że
while
jest zwykle bardziej wydajne niżfor-in
,forEach
itpźródło
i
zmienna lokalna nie jest obca?length
jest przekazywany przez wartość, więc powinieneś być w stanie bezpośrednio go zmniejszyć.arr[i] = value
.). O wiele szybciej jest przechodzić od początku do końca i używaćarr.push(value)
. To denerwujące, ponieważ wolę twoją metodę.za pomocą notacji obiektowej
zero wypełnione? lubić...
wypełnione „niezdefiniowanym” ...
notacja obj z zerami
Na marginesie, jeśli zmodyfikujesz prototyp Array, oba
i
będą miały te prototypowe modyfikacje
W każdym razie nie przejmowałbym się zbytnio wydajnością ani szybkością tej operacji, istnieje wiele innych rzeczy, które prawdopodobnie będziesz robić, które są o wiele bardziej marnotrawne i kosztowne niż wprowadzanie tablicy o dowolnej długości zawierającej zera.
źródło
null
w tej tablicy -var x = new Array(7);
new Array(7)
czy nie utworzyć tablicę „wypełnioną nieokreślone”. Tworzy pustą tablicę o długości 7.(new Array(10)).fill(0)
.Testowałem wszystkie kombinacje wstępnego przydzielania / nieprzydzielania wstępnego, liczenia w górę / w dół oraz pętli for / while w IE 6/7/8, Firefox 3.5, Chrome i Opera.
Poniższe funkcje były konsekwentnie najszybsze lub bardzo zbliżone w Firefoksie, Chrome i IE8 i niewiele wolniejsze niż najszybsze w Operze i IE 6. Jest to również najprostsze i najczystsze moim zdaniem. Znalazłem kilka przeglądarek, w których wersja pętli while jest nieco szybsza, więc dołączam ją również w celach informacyjnych.
lub
źródło
var array = []
deklarację do pierwszej części pętli for, oddzielonej przecinkiem.length
wartość już podaną, aby nie ulegała ciągłym zmianom. Na mojej maszynie przyniosłem tablicę 1 milion długości zer od 40 ms do 8.for (i = 0, array = []; i < length; ++i) array[i] = val;
.. Mniej bloków? ... w każdym razie także ... jeśliarray.length
ustawię nową tablicę na długość .. wydaje mi się, że dostanę kolejne 10% -15% zwiększenie prędkości FF ... w Chrome wydaje się, że podwoi prędkość ->var i, array = []; array.length = length; while(i < length) array[i++] = val;
(był jeszcze szybszy, gdybym zostawił go jakofor
pętlę ... ale init nie jest już potrzebny, więcwhile
wydaje się, że jest szybszy w tej wersji)Jeśli podczas wykonywania kodu musisz utworzyć wiele wypełnionych zerami tablic o różnych długościach, najszybszym sposobem, jaki udało mi się to osiągnąć, jest utworzenie tablicy zerowej jeden raz , przy użyciu jednej z metod wymienionych w tym temacie, o długości które, jak wiesz, nigdy nie zostanie przekroczone, a następnie pokrój tę tablicę w razie potrzeby.
Na przykład (używając funkcji z wybranej powyżej odpowiedzi do zainicjowania tablicy), utwórz tablicę wypełnioną zerami o długości maxLength , jako zmienną widoczną dla kodu, który potrzebuje tablic zerowych:
Teraz pokrój tę tablicę za każdym razem, gdy potrzebujesz wymaganej zerowej tablicy o wymaganej długości Długość < max Długość :
Podczas wykonywania mojego kodu tysiące razy tworzyłem tablice wypełnione zerami, co ogromnie przyspieszyło ten proces.
źródło
źródło
new Array(size+1).join("x").split("x").map(function() { return 0; })
do uzyskania rzeczywistych liczbnew Array(size+1).join('0').split('').map(Number)
Nie mam nic przeciwko:
sugerowane przez Zertosha, ale w nowych rozszerzeniach macierzy ES6 pozwala to robić natywnie za pomocą
fill
metody. Teraz IE edge, Chrome i FF obsługuje to, ale sprawdź tabelę kompatybilnościnew Array(3).fill(0)
da ci[0, 0, 0]
. Możesz wypełnić tablicę dowolną wartością, taką jaknew Array(5).fill('abc')
(nawet obiekty i inne tablice).Ponadto możesz modyfikować poprzednie tablice za pomocą fill:
co daje ci:
[1, 2, 3, 9, 9, 6]
źródło
Sposób, w jaki zwykle to robię (i jest niesamowicie szybki), to używanie
Uint8Array
. Na przykład, tworzenie wektora wypełnionego zerami elementów 1M:Jestem użytkownikiem Linuksa i zawsze dla mnie pracował, ale kiedyś znajomy korzystający z komputera Mac miał pewne niezerowe elementy. Myślałem, że jego maszyna działa nieprawidłowo, ale wciąż jest to najbezpieczniejszy sposób, aby go naprawić:
Edytowane
Chrome 25.0.1364.160
Firefox 20.0
Brakuje najważniejszego testu (przynajmniej dla mnie): Node.js. Podejrzewam, że jest zbliżony do testu porównawczego Chrome.
źródło
Za pomocą lodash lub podkreślenia
Lub jeśli masz tablicę i chcesz tablicę o tej samej długości
źródło
_.range(0, length, 0)
, wierzę. Lodash nie ma wartości końcowejRozwiązanie ES6:
źródło
Od ECMAScript2016 istnieje jeden jasny wybór dla dużych tablic.
Ponieważ ta odpowiedź wciąż pojawia się u góry w wynikach wyszukiwania Google, oto odpowiedź na rok 2017.
Oto aktualny jsbench z kilkoma popularnymi metodami, w tym wieloma zaproponowanymi do tej pory na to pytanie. Jeśli znajdziesz lepszą metodę, dodaj, rozwidlaj i udostępniaj.
Chcę zauważyć, że nie ma naprawdę najbardziej efektywnego sposobu na utworzenie tablicy o dowolnej długości wypełnionej zerą. Możesz zoptymalizować szybkość, jasność i łatwość konserwacji - albo można uznać, że jest to bardziej wydajny wybór w zależności od potrzeb projektu.
Podczas optymalizacji prędkości chcesz: utworzyć tablicę przy użyciu składni literalnej; ustaw długość, zainicjuj zmienną iteracyjną i iteruj po tablicy za pomocą pętli while. Oto przykład.
Inną możliwą implementacją byłoby:
Ale zdecydowanie odradzam stosowanie tej drugiej implantacji w praktyce, ponieważ jest ona mniej przejrzysta i nie pozwala zachować zakresu bloków w zmiennej tablicowej.
Są one znacznie szybsze niż wypełnianie pętli for i około 90% szybciej niż standardowa metoda
Jednak ta metoda wypełniania jest nadal najbardziej wydajnym wyborem dla mniejszych tablic ze względu na jej przejrzystość, zwięzłość i łatwość konserwacji. Różnica w wydajności prawdopodobnie Cię nie zabije, chyba że wykonasz wiele tablic o długości rzędu tysięcy lub więcej.
Kilka innych ważnych uwag. Większość przewodników po stylu zaleca, aby nie używać już
var
bez specjalnego powodu podczas używania ES6 lub nowszego. Użyjconst
dla zmiennych, które nie zostaną ponownie zdefiniowane, ilet
dla zmiennych, które będą. MDN i Airbnb za Style Guide to wspaniałe miejsca, aby znaleźć więcej informacji na temat najlepszych praktyk. Pytania nie dotyczyły składni, ale ważne jest, aby ludzie nowi w JS wiedzieli o tych nowych standardach podczas przeszukiwania tych rygli starych i nowych odpowiedzi.źródło
Aby utworzyć zupełnie nową macierz
Aby dodać niektóre wartości na końcu istniejącej tablicy
[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]
Przykład
źródło
Nie widziałem tej metody w odpowiedziach, więc oto ona:
W rezultacie otrzymasz tablicę o wartości zerowej o długości 200:
Nie jestem pewien wydajności tego kodu, ale nie powinno to stanowić problemu, jeśli używasz go do stosunkowo małych tablic.
źródło
źródło
Ta
concat
wersja jest znacznie szybsza w moich testach na Chrome (2013-03-21). Około 200 ms dla 10 000 000 elementów w porównaniu z 675 dla prostego init.Bonus: jeśli chcesz wypełnić tablicę ciągami, jest to zwięzły sposób na zrobienie tego (nie tak szybko, jak
concat
gdyby):źródło
Testowałem świetną odpowiedź TJ Crowdera i wymyśliłem rekurencyjne scalanie oparte na rozwiązaniu konkat, które przewyższa wszelkie w swoich testach w Chrome (nie testowałem innych przeglądarek).
wywołaj metodę za pomocą
makeRec(29)
.źródło
Co
new Array(51).join('0').split('')
?źródło
.map(function(a){return +a})
?Warto zauważyć, że
Array.prototype.fill
został dodany w ramach propozycji ECMAScript 6 (Harmonia) . Wolę pójść z polifillem napisanym poniżej, zanim rozważę inne opcje wymienione w wątku.źródło
Najkrótszy dla kodu pętli
Bezpieczna wersja var
źródło
n
byłaby ona krótsza:for(var a=[];n--;a[n]=0);
źródło
Moją najszybszą funkcją byłoby:
Używanie natywnego push i shift do dodawania elementów do tablicy jest znacznie szybsze (około 10 razy) niż deklarowanie zakresu tablicy i odwoływanie się do każdego elementu w celu ustawienia jego wartości.
fyi: Konsekwentnie otrzymuję szybsze czasy dzięki pierwszej pętli, która się odlicza, gdy uruchamiam to w firebug (rozszerzenie firefox).
Chcę wiedzieć, co robi z tego TJ Crowder? :-)
źródło
while (len--)
.. zabrało mi czas przetwarzania od około 60 ms do około 54 msWiedziałem, że mam gdzieś ten proto :)
Edycja: testy
W odpowiedzi na Joshua i inne metody przeprowadziłem własne testy porównawcze i widzę zupełnie inne wyniki niż te zgłoszone.
Oto co przetestowałem:
Wyniki:
Według mojego obliczenia push jest generalnie wolniejszy, ale działa lepiej z dłuższymi tablicami w FF, ale gorzej w IE, który po prostu jest do kitu (niespodzianka quel).
źródło
b = []...
) jest 10-15% szybsza niż pierwsza, ale jest ponad 10 razy wolniejsza niż odpowiedź Jozuego.else {this.length=n;}
pothis.length
-Check. W razie potrzeby skróci to już istniejącą tablicę podczas ponownejinit
inicjalizacji jej do innej długościn
.Funkcja anonimowa:
Nieco krótszy z pętlą for:
Działa z każdym
Object
, wystarczy zmienić to, co jest w środkuthis.push()
.Możesz nawet zapisać funkcję:
Zadzwoń, używając:
Dodawanie elementów do już istniejącej tablicy:
Wydajność: http://jsperf.com/zero-filled-array-creation/25
źródło