JavaScript'te rasgele uzunluk sıfır dolu dizi oluşturmanın en etkili yolu nedir?
let i = 0; Array.from(Array(10), ()=>i++);
JavaScript'te rasgele uzunluk sıfır dolu dizi oluşturmanın en etkili yolu nedir?
let i = 0; Array.from(Array(10), ()=>i++);
Yanıtlar:
ES6 tanıtıyor Array.prototype.fill
. Bu şekilde kullanılabilir:
new Array(len).fill(0);
Hızlı olup olmadığından emin değilim, ama hoşuma gidiyor çünkü kısa ve kendini tarif ediyor.
Hala IE'de değil ( uyumluluğu kontrol edin ), ancak kullanılabilir bir çoklu dolgu var .
new Array(len)
acı verici yavaştır. (arr = []).length = len; arr.fill(0);
herhangi bir yerde görülen en hızlı çözüm hakkında ... ya da en azından bağlı
arr = Array(n)
ve (arr = []).length = n
şartnameye göre aynı şekilde davranır. Bazı uygulamalarda daha hızlı olabilir, ancak büyük bir fark olduğunu düşünmüyorum.
(arr = []).length = 1000;
karşı bu satırı kullanmak arr = new Array(1000);
... new
çok yavaş. Şimdi, daha küçük dizi uzunlukları için .. <50 ya da orada hakkında ... sonra new Array()
daha iyi performans gibi görünüyor. But ..
arr.fill(0)
... her şey değişti. Şimdi, new Array()
100000'den büyük dizi boyutlarına erişmeniz dışında çoğu durumda kullanmak daha hızlıdır ... Sonra hız artışını tekrar görmeye başlayabilirsiniz. Ama aslında sıfırlarla doldurmak zorunda değilsiniz ve boş dizilerin standart yanlışını kullanabilirsiniz. Sonra (arr = []).length = x
çoğu zaman test vakalarımda çılgınca.
new Array(5).forEach(val => console.log('hi'));
vs new Array(5).fill(undefined).forEach(val => console.log('hi'));
.
Bu eski bir iş parçacığı olmasına rağmen, 2 sent eklemek istedim. Bunun ne kadar yavaş / hızlı olduğundan emin değilim, ama hızlı bir astar. İşte yaptığım şey:
Bir numarayla önceden doldurmak istersem:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]
Bir dize ile önceden doldurmak isterseniz:
Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]
Diğer cevaplar önerdi:
new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]
ancak "0" (bir dize içinde sıfır) istemiyorsanız 0 (sayı) istiyorsanız şunları yapabilirsiniz:
new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]
Array.apply(null, new Array(5)).map(...)
? Çünkü basitçe yapıyor (yeni Dizi (5)). Harita (...) spesifikasyonun söylediği gibi çalışmaz
new
) Bunu yaptığınızda Array(5)
şöyle görünen bir nesne yaratıyorsunuz: { length: 5, __proto__: Array.prototype }
- deneyin console.dir( Array(5) )
. Bildirim herhangi özelliklere sahip olmadığını 0
, 1
, 2
vb Ama sizi zaman apply
şöyle böyle Array
yapıcı, bu demek gibi Array(undefined, undefined, undefined, undefined, undefined)
. Ve biraz benzeyen bir nesne elde edersiniz { length: 5, 0: undefined, 1: undefined...}
. map
özellikleri 0
, 1
vb. üzerinde çalışır, bu nedenle örneğiniz çalışmaz, ancak kullandığınızda apply
çalışır.
.apply
aslında olmasını istediğiniz şeydir this
. Bu amaçlar için this
önemli değil - sadece parametrenin "özelliğini" yaymakla ilgileniyoruz .apply
- bu yüzden herhangi bir değer olabilir. Beğendim null
çünkü ucuz, muhtemelen kullanmak istemiyorsunuz {}
veya []
bir nesneyi sebepsiz yere somutlaştırdığınız için.
İşte ES6'yı kullanarak kimsenin bahsetmediği başka bir yol:
> Array.from(Array(3), () => 0)
< [0, 0, 0]
Bir harita fonksiyonunu ikinci parametre olarak geçirerek çalışır Array.from
.
Yukarıdaki örnekte, ilk parametre değerle dolu 3 konumlu bir dizi undefined
ayırır ve sonra lambda işlevi her birini değere eşler 0
.
Her ne kadar Array(len).fill(0)
daha kısa olsa da, önce bazı hesaplama yaparak diziyi doldurmanız gerekiyorsa işe yaramaz (sorunun sorulmadığını biliyorum, ancak birçok insan burada bunu arıyor) .
Örneğin, 10 rasgele sayı içeren bir diziye ihtiyacınız varsa:
> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]
Eşdeğerden daha özlü (ve zarif):
const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
numbers[i] = Math.round(10 * Math.random());
}
Bu yöntem, geri aramada sağlanan dizin parametresinden yararlanarak numara dizileri oluşturmak için de kullanılabilir:
> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
repeat()
Bu cevap çok dikkat çektiğinden, bu havalı hileyi de göstermek istedim. Benim ana cevap kadar yararlı olmasa da, hala çok bilinmeyen, ama çok yararlı String repeat()
yöntemini tanıtacaktır . İşte hile:
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
Havalı değil mi? repeat()
orijinal dizenin belirli sayıda yinelenmesi olan bir dize oluşturmak için çok kullanışlı bir yöntemdir. Bundan sonra, split()
bizim için bir dizi oluşturur, bu daha sonra map()
istediğimiz değerlere ayak uydurur. Adımlarla yıkmak:
> "?".repeat(10)
< "??????????"
> "?".repeat(10).split("")
< ["?", "?", "?", "?", "?", "?", "?", "?", "?", "?"]
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
repeat
Hile kesinlikle üretimde Array.from()
En hızlı çözüm
let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;
En kısa (kullanışlı) çözüm (küçük diziler için 3 kat daha yavaş, büyükler için biraz daha yavaş (Firefox'ta en yavaş))
Array(n).fill(0)
Bugün 2020.06.09 Chrome 83.0, Firefox 77.0 ve Safari 13.1 tarayıcılarında macOS High Sierra 10.13.6 üzerinde testler yapıyorum. İki test vakası için seçilen çözümleri test ediyorum
new Array(n)+for
(N) tabanlı çözüm, küçük diziler ve büyük diziler için en hızlı çözümdür (Chrome hariç ancak yine de çok hızlıdır) ve hızlı çapraz tarayıcı çözümü olarak önerilirnew Float32Array(n)
(I) 'ye dayalı çözüm, tipik olmayan bir dizi döndürür (örneğin, bunu çağıramazsınız) push(..)
, bu yüzden sonuçlarını diğer çözümlerle karşılaştırmam - ancak bu çözüm, tüm tarayıcılardaki büyük diziler için diğer çözümlerden yaklaşık 10-20x daha hızlıdırfor
(L, M, N, O) tabanlı çözümler küçük diziler için hızlıdırfill
(B, C) tabanlı çözümler Chrome ve Safari'de hızlı, ancak büyük diziler için Firefox'ta şaşırtıcı derecede yavaştır. Küçük diziler için orta hızlıdırArray.apply
(P) 'ye dayalı çözüm büyük diziler için hata atar
Aşağıdaki kod ölçümlerde kullanılan çözümleri sunar
Chrome için örnek sonuçlar
let a=[]; for(i=n;i--;) a.push(0);
- ama bundan 4 kat daha yavaş fill(0)
- bu yüzden resim cadı güncellemeyeceğim bile.
Daha önce bahsedilen ES 6 doldurma yöntemi bunu iyi halleder. Çoğu modern masaüstü tarayıcısı bugün itibariyle gerekli Array prototip yöntemlerini desteklemektedir (Chromium, FF, Edge ve Safari) [ 1 ]. MDN ile ilgili ayrıntıları arayabilirsiniz . Basit bir kullanım örneği
a = new Array(10).fill(0);
Mevcut tarayıcı desteği verildiğinde, kitlenizin modern Masaüstü tarayıcıları kullandığından emin olmadığınız sürece bunu kullanmaya dikkat etmelisiniz.
a = Array(10).fill(null).map(() => { return []; });
a = Array(10).fill(0).map( _ => [] );
Not Ağustos 2013, güncellenmiş Şubat 2015 eklendi: 2009'dan aşağıdaki cevap JavaScript'in genel Array
türü ile ilgilidir . ES2015'te tanımlanan (ve şimdi birçok tarayıcıda kullanılabilir), vb. Gibi daha yeni yazılan dizilerle ilgili değildir Int32Array
. Ayrıca ES2015 bir ekler dikkat fill
hem yöntemini Dizileri ve daktilo diziler bunları doldurmak için en verimli şekilde olması muhtemeldir, ...
Ayrıca, diziyi nasıl oluşturduğunuzda bazı uygulamalarda büyük fark yaratabilir. Özellikle Chrome'un V8 motoru, yalnızca gerektiğinde nesne tabanlı diziye geçerek, olabileceğini düşünüyorsa yüksek verimli, bitişik bir bellek dizisi kullanmaya çalışır.
Çoğu dilde, önceden tahsis edildikten sonra sıfır doldurulur, şöyle:
function newFilledArray(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = val;
}
return rv;
}
Ancak , JavaScript dizileri gerçekte diziler değildir , tıpkı diğer tüm JavaScript nesneleri gibi anahtar / değer haritalarıdır, bu nedenle yapılacak "ön ayırma" yoktur (uzunluğu ayarlamak, birçok alanı doldurmak için ayırmaz) veya Uygulama, anahtarların işlenmesini optimize ettiğinde anahtarları ters sırayla ekleyerek sıfıra geri saymanın (yalnızca döngüdeki karşılaştırmayı hızlı hale getirmek için) daha fazla olmadığına inanmak için herhangi bir neden var mı? teoriye göre dizilerle ilgili olarak bunları genellikle sırayla yaparsınız.
Aslında, Matthew Crumley, geri sayımın Firefox'ta sayımdan belirgin şekilde daha yavaş olduğunu, onaylayabildiğim bir sonuç olduğuna dikkat çekti - bunun dizi kısmı (sıfıra inmek hala bir var olan bir sınıra kadar döngüden daha hızlı). Görünüşe göre öğeleri diziye ters sırayla eklemek Firefox'ta yavaş bir işlemdir. Aslında, sonuçlar JavaScript uygulamasıyla oldukça değişkendir (bu şaşırtıcı değildir). İşte tarayıcı uygulamaları için hızlı ve kirli bir test sayfası (aşağıda) (çok kirli, testler sırasında verim yok, bu nedenle minimum geri bildirim sağlar ve komut dosyası zaman sınırları ile çalışır). Testler arasında yenilenmeyi öneriyorum; Eğer yapmazsanız FF (en azından) tekrarlanan testlerde yavaşlar.
Array # concat kullanan oldukça karmaşık sürüm, 1.000 ila 2.000 eleman dizisi arasında bir yerde olduğu gibi FF'deki düz bir başlatmadan daha hızlıdır. Bununla birlikte, Chrome'un V8 motorunda her seferinde düz init kazanıyor ...
İşte test sayfası ( canlı kopya ):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Zero Init Test Page</title>
<style type='text/css'>
body {
font-family: sans-serif;
}
#log p {
margin: 0;
padding: 0;
}
.error {
color: red;
}
.winner {
color: green;
font-weight: bold;
}
</style>
<script type='text/javascript' src='prototype-1.6.0.3.js'></script>
<script type='text/javascript'>
var testdefs = {
'downpre': {
total: 0,
desc: "Count down, pre-decrement",
func: makeWithCountDownPre
},
'downpost': {
total: 0,
desc: "Count down, post-decrement",
func: makeWithCountDownPost
},
'up': {
total: 0,
desc: "Count up (normal)",
func: makeWithCountUp
},
'downandup': {
total: 0,
desc: "Count down (for loop) and up (for filling)",
func: makeWithCountDownArrayUp
},
'concat': {
total: 0,
desc: "Concat",
func: makeWithConcat
}
};
document.observe('dom:loaded', function() {
var markup, defname;
markup = "";
for (defname in testdefs) {
markup +=
"<div><input type='checkbox' id='chk_" + defname + "' checked>" +
"<label for='chk_" + defname + "'>" + testdefs[defname].desc + "</label></div>";
}
$('checkboxes').update(markup);
$('btnTest').observe('click', btnTestClick);
});
function epoch() {
return (new Date()).getTime();
}
function btnTestClick() {
// Clear log
$('log').update('Testing...');
// Show running
$('btnTest').disabled = true;
// Run after a pause while the browser updates display
btnTestClickPart2.defer();
}
function btnTestClickPart2() {
try {
runTests();
}
catch (e) {
log("Exception: " + e);
}
// Re-enable the button; we don't yheidl
$('btnTest').disabled = false;
}
function runTests() {
var start, time, counter, length, defname, def, results, a, invalid, lowest, s;
// Get loops and length
s = $F('txtLoops');
runcount = parseInt(s);
if (isNaN(runcount) || runcount <= 0) {
log("Invalid loops value '" + s + "'");
return;
}
s = $F('txtLength');
length = parseInt(s);
if (isNaN(length) || length <= 0) {
log("Invalid length value '" + s + "'");
return;
}
// Clear log
$('log').update('');
// Do it
for (counter = 0; counter <= runcount; ++counter) {
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
start = epoch();
a = def.func(length);
time = epoch() - start;
if (counter == 0) {
// Don't count (warm up), but do check the algorithm works
invalid = validateResult(a, length);
if (invalid) {
log("<span class='error'>FAILURE</span> with def " + defname + ": " + invalid);
return;
}
}
else {
// Count this one
log("#" + counter + ": " + def.desc + ": " + time + "ms");
def.total += time;
}
}
}
}
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
def.avg = def.total / runcount;
if (typeof lowest != 'number' || lowest > def.avg) {
lowest = def.avg;
}
}
}
results =
"<p>Results:" +
"<br>Length: " + length +
"<br>Loops: " + runcount +
"</p>";
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
results += "<p" + (lowest == def.avg ? " class='winner'" : "") + ">" + def.desc + ", average time: " + def.avg + "ms</p>";
}
}
results += "<hr>";
$('log').insert({top: results});
}
function validateResult(a, length) {
var n;
if (a.length != length) {
return "Length is wrong";
}
for (n = length - 1; n >= 0; --n) {
if (a[n] != 0) {
return "Index " + n + " is not zero";
}
}
return undefined;
}
function makeWithCountDownPre(len) {
var a;
a = new Array(len);
while (--len >= 0) {
a[len] = 0;
}
return a;
}
function makeWithCountDownPost(len) {
var a;
a = new Array(len);
while (len-- > 0) {
a[len] = 0;
}
return a;
}
function makeWithCountUp(len) {
var a, i;
a = new Array(len);
for (i = 0; i < len; ++i) {
a[i] = 0;
}
return a;
}
function makeWithCountDownArrayUp(len) {
var a, i;
a = new Array(len);
i = 0;
while (--len >= 0) {
a[i++] = 0;
}
return a;
}
function makeWithConcat(len) {
var a, rem, currlen;
if (len == 0) {
return [];
}
a = [0];
currlen = 1;
while (currlen < len) {
rem = len - currlen;
if (rem < currlen) {
a = a.concat(a.slice(0, rem));
}
else {
a = a.concat(a);
}
currlen = a.length;
}
return a;
}
function log(msg) {
$('log').appendChild(new Element('p').update(msg));
}
</script>
</head>
<body><div>
<label for='txtLength'>Length:</label><input type='text' id='txtLength' value='10000'>
<br><label for='txtLoops'>Loops:</label><input type='text' id='txtLoops' value='10'>
<div id='checkboxes'></div>
<br><input type='button' id='btnTest' value='Test'>
<hr>
<div id='log'></div>
</div></body>
</html>
Varsayılan Uint8Array
olarak Uint16Array
ve Uint32Array
sınıflar sıfırları değerleri olarak tutar, bu nedenle karmaşık doldurma tekniklerine ihtiyacınız yoktur, sadece şunları yapın:
var ary = new Uint8Array(10);
dizinin tüm öğeleri ary
varsayılan olarak sıfır olacaktır.
Array.isArray(ary)
olduğunu false
. Uzunluk da salt okunur olduğundan, yeni öğeleri olduğu gibi ary.push
0
varsayılan değer olarak tutar.
Array.from(new Uint8Array(10))
normal bir dizi sağlar.
Array(n).fill(0)
gerçekten ihtiyacınız olan bir JS Dizisi ise Chrome'dan yaklaşık 5 kat daha yavaş olduğunu gösteriyor . TypedArray kullanabiliyorsanız .fill(0)
, özellikle de varsayılan başlatıcı değerini kullanabiliyorsanız bu çok daha hızlıdır 0
. C ++ 'ın std::vector
sahip olduğu gibi bir dolgu değeri ve uzunluğu alan bir kurucu yok gibi görünüyor . Sıfır olmayan herhangi bir değer için, sıfırlanmış bir TypedArray oluşturmanız ve sonra doldurmanız gerekir. : /
ES6 kullanıyorsanız, aşağıdaki gibi Array.from () kullanabilirsiniz :
Array.from({ length: 3 }, () => 0);
//[0, 0, 0]
İle aynı sonuca sahiptir
Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]
Çünkü
Array.from({ length: 3 })
//[undefined, undefined, undefined]
function makeArrayOf(value, length) {
var arr = [], i = length;
while (i--) {
arr[i] = value;
}
return arr;
}
makeArrayOf(0, 5); // [0, 0, 0, 0, 0]
makeArrayOf('x', 3); // ['x', 'x', 'x']
Not while
genellikle daha etkilidir for-in
, forEach
vb
i
yerel değişken gereksiz? length
değeri geçerek doğrudan azaltabiliyor olmanız gerekir.
arr[i] = value
). Başından sonuna kadar döngü yapmak ve kullanmak çok daha hızlı arr.push(value)
. Bu sinir bozucu, çünkü yönteminizi tercih ediyorum.
nesne gösterimini kullanma
var x = [];
sıfır dolu mu? sevmek...
var x = [0,0,0,0,0,0];
'undefined' ile dolu ...
var x = new Array(7);
sıfırlarla obj gösterimi
var x = [];
for (var i = 0; i < 10; i++) x[i] = 0;
Bir yan not olarak, Array'ın prototipini değiştirirseniz, her ikisi de
var x = new Array();
ve
var y = [];
bu prototip değişikliklerine sahip olacak
Her halükarda, bu operasyonun verimliliği veya hızı ile aşırı derecede ilgilenmiyorum, muhtemelen sıfırlar içeren bir dizi rasgele uzunluk oluşturmaya kıyasla çok daha israf ve pahalı olacak başka şeyler de var.
null
Bu dizide hiç s yok -var x = new Array(7);
new Array(7)
yok değil bir dizi "tanımlanmamış ile dolu" oluşturun. Uzunluğu 7 olan boş bir dizi oluşturur .
(new Array(10)).fill(0)
.
IE 6/7/8, Firefox 3.5, Chrome ve Opera'da ön ayırma / ön ayırmama, yukarı / aşağı sayma ve döngüler için tüm kombinasyonları test ettim.
Aşağıdaki işlevler Firefox, Chrome ve IE8'de sürekli olarak en hızlı veya son derece yakındı ve Opera ve IE 6'daki en hızlıdan çok daha yavaş değildi. While döngüsü sürümünün biraz daha hızlı olduğu birkaç tarayıcı buldum, bu yüzden referans için de dahil ediyorum.
function newFilledArray(length, val) {
var array = [];
for (var i = 0; i < length; i++) {
array[i] = val;
}
return array;
}
veya
function newFilledArray(length, val) {
var array = [];
var i = 0;
while (i < length) {
array[i++] = val;
}
return array;
}
var array = []
bildirimi yalnızca virgülle ayrılmış olarak for döngüsünün ilk kısmına da atabilirsiniz .
length
sürekli olarak değişmeyecek şekilde önceden verilen değere ayarlayın . Makinemde 40 milyondan 8'e 1 milyon uzunlukluk sıfır dizi getirdik.
for (i = 0, array = []; i < length; ++i) array[i] = val;
.. Daha az blok mu? ... her neyse, ayrıca ... eğer array.length
yeni diziyi uzunluğa ayarlarsam .. FF'de% 10 -% 15'lik bir başka hız artışı görüyorum ... Chrome'da, hızı iki katına çıkıyor gibi görünüyor -> var i, array = []; array.length = length; while(i < length) array[i++] = val;
(bir for
döngü olarak bıraktığımda hala daha hızlıydı ... ama init artık gerekli değil, bu yüzden while
bu sürümde daha hızlı görünüyor)
Kodunuzun yürütülmesi sırasında farklı uzunluklarda sıfır dolu diziler oluşturmanız gerekiyorsa, bunu başarmanın en hızlı yolu , bu konuda belirtilen yöntemlerden birini kullanarak bir kez sıfır dizi oluşturmaktır. asla aşılmayacağını bildiğiniz bir diziyi gerektiği gibi dilimleyin.
Örneğin (diziyi başlatmak için yukarıdaki seçili cevaptaki işlevi kullanarak), sıfır diziye ihtiyaç duyan kodun görebileceği bir değişken olarak sıfır dolu uzunluk maxLength dizisi oluşturun:
var zero = newFilledArray(maxLength, 0);
Şimdi uzunluğu bir sıfır dolu dizi gerek bu dizi her şey dilim requiredLength < maxLength :
zero.slice(0, requiredLength);
Kodumun yürütülmesi sırasında binlerce kez sıfır dolu diziler oluşturuyordum, bu süreci çok hızlandırdı.
Karşı hiçbir şeyim yok:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);
Zertosh tarafından önerilen, ancak yeni bir ES6 dizi uzantısında bunu fill
yöntemle yerel olarak yapmanızı sağlar . Şimdi IE edge, Chrome ve FF destekliyor, ancak uyumluluk tablosunu kontrol edin
new Array(3).fill(0)
verecek [0, 0, 0]
. Diziyi herhangi bir değerle new Array(5).fill('abc')
(hatta nesneler ve diğer diziler) doldurabilirsiniz .
Üstelik önceki dizileri dolgu ile değiştirebilirsiniz:
arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5) # what to fill, start, end
hangi size verir: [1, 2, 3, 9, 9, 6]
Genellikle yaptığım (ve inanılmaz hızlı) yolu kullanıyor Uint8Array
. Örneğin, 1M öğelerinin sıfır dolu bir vektörü oluşturma:
var zeroFilled = [].slice.apply(new Uint8Array(1000000))
Ben bir Linux kullanıcısıyım ve her zaman benim için çalıştım, ancak Mac kullanan bir arkadaşın sıfır olmayan elementleri vardı. Makinesinin arızalı olduğunu düşündüm, ancak yine de düzeltmek için bulduğumuz en güvenli yol:
var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000))
Düzenlenen
Krom 25.0.1364.160
Firefox 20.0
En önemli testi (en azından benim için) eksik: Node.js. Chrome karşılaştırmasına yakın olduğundan şüpheleniyorum.
Lodash veya alt çizgi kullanma
_.range(0, length - 1, 0);
Veya mevcut bir diziniz varsa ve aynı uzunlukta bir dizi istiyorsanız
array.map(_.constant(0));
_.range(0, length, 0)
, inanıyorum. Lodash son değeri hariç
ECMAScript2016 itibarıyla büyük diziler için açık bir seçenek vardır.
Bu yanıt Google aramalarında hala en üstte göründüğünden, 2017 için bir cevap.
İşte bu soruya şimdiye kadar teklif edilenler de dahil olmak üzere birkaç düzine popüler yöntemle mevcut bir jsbench . Daha iyi bir yöntem bulursanız lütfen ekleyin, çatallayın ve paylaşın.
Ben rastgele uzunluk sıfır dolu dizi oluşturmak için gerçek en verimli yolu olmadığını not etmek istiyorum. Hız veya netlik ve sürdürülebilirlik için optimize edebilirsiniz - ya projenin ihtiyaçlarına bağlı olarak daha verimli bir seçim olarak düşünülebilir.
Hız için optimizasyon yaparken aşağıdakileri yapmak istersiniz: değişmez sözdizimini kullanarak dizi oluşturmak; uzunluğu ayarlayın, yineleme değişkenini başlatın ve bir while döngüsü kullanarak dizi boyunca yineleyin. İşte bir örnek.
const arr = [];
arr.length = 120000;
let i = 0;
while (i < 120000) {
arr[i] = 0;
i++;
}
Başka bir olası uygulama:
(arr = []).length = n;
let i = 0;
while (i < n) {
arr[i] = 0;
i++;
}
Ancak, daha az net olduğu ve dizi değişkeniniz üzerinde blok kapsamını korumanıza izin vermediğinden, bu ikinci implantasyonu pratikte kullanmayı kesinlikle tavsiye etmiyorum.
Bunlar bir for döngüsü ile doldurmaktan önemli ölçüde daha hızlıdır ve standart yöntemden yaklaşık% 90 daha hızlıdır.
const arr = Array(n).fill(0);
Ancak bu doldurma yöntemi, açıklığı, kısalığı ve sürdürülebilirliği nedeniyle daha küçük diziler için hala en verimli seçimdir. Binlerce veya daha fazla uzunlukta uzunlukları olan çok sayıda dizi yapmadığınız sürece performans farkı muhtemelen sizi öldürmez.
Birkaç önemli not daha. Çoğu stil kılavuzu var
, ES6 veya daha yenisini kullanırken artık çok özel bir neden olmadan kullanmamanızı önerir. const
Yeniden tanımlanamayan let
değişkenler ve değişkenler için kullanın . MDN ve Airbnb en Stil Kılavuzu en iyi uygulamalar hakkında daha fazla bilgi için gitmek için harika yerlerdir. Sorular sözdizimi ile ilgili değildi, ancak JS'de yeni insanların bu eski ve yeni cevaplar arasında arama yaparken bu yeni standartları bilmesi önemlidir.
Yepyeni bir Dizi oluşturmak için
new Array(arrayLength).fill(0);
Mevcut bir Dizinin sonuna bazı değerler eklemek için
[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]
//**To create an all new Array**
console.log(new Array(5).fill(0));
//**To add some values at the end of an existing Array**
let existingArray = [1,2,3]
console.log([...existingArray, ...new Array(5).fill(0)]);
Cevaplarda bu yöntemi görmedim, işte burada:
"0".repeat( 200 ).split("").map( parseFloat )
Sonuç olarak, sıfır değerli uzunluk 200 dizisini alırsınız:
[ 0, 0, 0, 0, ... 0 ]
Bu kodun performansı hakkında emin değilim, ancak nispeten küçük diziler için kullanırsanız bir sorun olmamalıdır.
const arr = Array.from({ length: 10 }).fill(0)
Bu concat
sürüm, Chrome'daki (2013-03-21) testlerimde çok daha hızlı. 10.000.000 eleman için 200ms ve düz init için 675.
function filledArray(len, value) {
if (len <= 0) return [];
var result = [value];
while (result.length < len/2) {
result = result.concat(result);
}
return result.concat(result.slice(0, len-result.length));
}
Bonus: Dizinizi Dizeler ile doldurmak istiyorsanız, bunu yapmanın kısa bir yoludur ( concat
sanki o kadar hızlı değil ):
function filledArrayString(len, value) {
return new Array(len+1).join(value).split('');
}
TJ Crowder'ın büyük cevabını test ediyordum ve Chrome'daki testlerinde herhangi bir performanstan daha iyi performans gösteren concat çözümüne dayanan yinelemeli birleştirme ile geldim (diğer tarayıcıları test etmedim).
function makeRec(len, acc) {
if (acc == null) acc = [];
if (len <= 1) return acc;
var b = makeRec(len >> 1, [0]);
b = b.concat(b);
if (len & 1) b = b.concat([0]);
return b;
},
yöntemi ile çağırın makeRec(29)
.
ECMAScript 6 (Harmony) teklifinin birArray.prototype.fill
parçası olarak eklenmiş olduğunu belirtmek gerekir . Ben iplik üzerinde belirtilen diğer seçenekleri düşünmeden önce, aşağıda yazılı çok dolgu ile gitmek istiyorum.
if (!Array.prototype.fill) {
Array.prototype.fill = function(value) {
// Steps 1-2.
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
// Steps 3-5.
var len = O.length >>> 0;
// Steps 6-7.
var start = arguments[1];
var relativeStart = start >> 0;
// Step 8.
var k = relativeStart < 0 ?
Math.max(len + relativeStart, 0) :
Math.min(relativeStart, len);
// Steps 9-10.
var end = arguments[2];
var relativeEnd = end === undefined ?
len : end >> 0;
// Step 11.
var final = relativeEnd < 0 ?
Math.max(len + relativeEnd, 0) :
Math.min(relativeEnd, len);
// Step 12.
while (k < final) {
O[k] = value;
k++;
}
// Step 13.
return O;
};
}
Döngü kodu için en kısa
a=i=[];for(;i<100;)a[i++]=0;
edit:
for(a=i=[];i<100;)a[i++]=0;
or
for(a=[],i=100;i--;)a[i]=0;
Güvenli değişken sürümü
var a=[],i=0;for(;i<100;)a[i++]=0;
edit:
for(var i=100,a=[];i--;)a[i]=0;
n
, bu daha kısa olacaktır:for(var a=[];n--;a[n]=0);
let filled = [];
filled.length = 10;
filled.fill(0);
console.log(filled);
En hızlı fonksiyonum:
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
var st = (new Date()).getTime();
newFilledArray(1000000, 0)
console.log((new Date()).getTime() - st); // returned 63, 65, 62 milliseconds
Diziye öğe eklemek için yerel itme ve kaydırma özelliğini kullanmak, dizi kapsamını bildirmekten ve değerini ayarlamak için her öğeye başvurmaktan çok daha hızlıdır (yaklaşık 10 kez).
fyi: Firebug'da (firefox uzantısı) çalıştırırken geri sayan ilk döngü ile sürekli daha hızlı zamanlar alıyorum.
var a = [];
var len = 1000000;
var st = (new Date()).getTime();
while(len){
a.push(0);
len -= 1;
}
console.log((new Date()).getTime() - st); // returned 863, 894, 875 milliseconds
st = (new Date()).getTime();
len = 1000000;
a = [];
for(var i = 0; i < len; i++){
a.push(0);
}
console.log((new Date()).getTime() - st); // returned 1155, 1179, 1163 milliseconds
TJ Crowder'ın bundan ne yaptığını bilmek isterim? :-)
while (len--)
.. işlem sürelerimi yaklaşık 60ms'den 54ms'ye çıkardı
Bu prototipin bir yerlerde olduğunu biliyordum :)
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
var a = (new Array(5)).init(0);
var b = [].init(0,4);
Düzenleme: testler
Joshua ve diğer yöntemlere yanıt olarak kendi kıyaslamamı yaptım ve bildirilenlerden tamamen farklı sonuçlar görüyorum.
İşte test ettiklerim:
//my original method
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
//now using push which I had previously thought to be slower than direct assignment
Array.prototype.init2 = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this.push(x); }
return this;
}
//joshua's method
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
//test m1 and m2 with short arrays many times 10K * 10
var a = new Date();
for(var i=0; i<10000; i++)
{
var t1 = [].init(0,10);
}
var A = new Date();
var b = new Date();
for(var i=0; i<10000; i++)
{
var t2 = [].init2(0,10);
}
var B = new Date();
//test m1 and m2 with long array created once 100K
var c = new Date();
var t3 = [].init(0,100000);
var C = new Date();
var d = new Date();
var t4 = [].init2(0,100000);
var D = new Date();
//test m3 with short array many times 10K * 10
var e = new Date();
for(var i=0; i<10000; i++)
{
var t5 = newFilledArray(10,0);
}
var E = new Date();
//test m3 with long array created once 100K
var f = new Date();
var t6 = newFilledArray(100000, 0)
var F = new Date();
Sonuçlar:
IE7 deltas:
dA=156
dB=359
dC=125
dD=375
dE=468
dF=412
FF3.5 deltas:
dA=6
dB=13
dC=63
dD=8
dE=12
dF=8
Yani benim hesaplaşma itme ile gerçekten genel olarak daha yavaş ama FF daha uzun diziler ile daha iyi performans ama IE genel olarak sadece kötü berbat (quel sürpriz).
b = []...
) birinciden % 10-15 daha hızlı, ancak Joshua'nın cevabından 10 kat daha yavaş.
else {this.length=n;}
sonra this.length
. Bu, gerektiğinde mevcut bir diziyi init
farklı bir uzunluğa yeniden ayarlarken kısaltacaktır n
.
Anonim işlev:
(function(n) { while(n-- && this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
For-loop ile biraz daha kısa:
(function(n) { for(;n--;this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Herhangi biriyle çalışır Object
, sadece içindekileri değiştirin this.push()
.
Hatta işlevi kaydedebilirsiniz:
function fill(size, content) {
for(;size--;this.push(content));
return this;
}
Şunu kullanarak arayın:
var helloArray = fill.call([], 5, 'hello');
// => ['hello', 'hello', 'hello', 'hello', 'hello']
Mevcut bir diziye eleman ekleme:
var helloWorldArray = fill.call(helloArray, 5, 'world');
// => ['hello', 'hello', 'hello', 'hello', 'hello', 'world', 'world', 'world', 'world', 'world']
Performans: http://jsperf.com/zero-filled-array-creation/25