1… N içeren bir dizi nasıl oluşturulur


1163

Ben N sadece çalışma zamanında bilinen 1 ila N içeren bir JavaScript dizisi oluşturmak için aşağıdaki herhangi bir alternatif arıyorum.

var foo = [];

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

Bana göre bunu döngü olmadan yapmanın bir yolu olmalı gibi geliyor.


224
Tüm sayfayı okuduktan sonra, kendi basit for-loop'unuzun en basit, en okunabilir ve en az hataya meyilli olduğu sonucuna vardım.
Kokodoko

Birinin daha gelişmiş bir şeye ihtiyacı varsa, bunu sayılar, harfler, negatif / pozitif aralıklar vb. İçin yapan bir node.js kütüphanesi oluşturdum . Github.com/jonschlinkert/fill-range . Bu içinde kullanılan github.com/jonschlinkert/braces bağ genişletme ve için github.com/jonschlinkert/micromatch glob modelleri için
jonschlinkert

1
"... 1 ... N" içeren yerine "N uzunluğunda bir dizi nasıl oluşturulur" demek için düzenlemelisiniz, ikincisi 1 ile N arasında değerlere sahip öğeler olacağını ima eder
Steven Landow

7
@StevenLandow OP neden yeniden adlandırılmalı? Değerleri olan bir dizi 1 ... Nmi istiyor ?
Andre Elrico

Güzel soru, güzel başlık, (saçma sapan cevaplar).
Bitterblue

Yanıtlar:


381

Eğer peşinde olduğun şeyi alırsam 1..n, sonradan geçebileceğin bir dizi sayı istersin.

Tüm ihtiyacınız olan bu ise, bunun yerine bunu yapabilir misiniz?

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

kullanmak istediğinizde ... (optimize edilmemiş, örneğin)

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

Örneğin , dizide herhangi bir şey depolamanız gerekmiyorsa, yalnızca yineleyebileceğiniz doğru uzunlukta bir kaba ihtiyacınız vardır ... bu daha kolay olabilir.

Burada iş başında görün: http://jsfiddle.net/3kcvm/


4
sorumu benden daha iyi ifade etmeyi başardığınızdan etkilendim, yansıma konusunda gerçekten haklısınız, daha sonra döngü yapabileceğim sayılar dizisi :) Cevabınız için teşekkürler.
Godders

147
@Godders: Aradığınız şey buysa, neden bir diziye ihtiyacınız var? Basit var n = 45;ve sonra gelen döngü 1..nyapardı.
casablanca

3
@Godders - Dizinin boyutunu M uzunluğuna oluşturulduktan sonra azaltmak istiyorsanız, şunu kullanın: foo.length = M--- Kesme bilgisi kaybolur. Hareket halinde görün ==> jsfiddle.net/ACMXp
Peter Ajtai

24
Gerçekten neden bu cevap upvotes var alamadım ... özellikle OP kendisi kabul ederse o sadece yapabilirdi çünkü yukarıdaki birkaç yorumda hiçbir mantıklı değil var n = 45;.
plalx

72
@scunliffe: Lütfen new Array(45);bunun "45 elemanlı bir dizi yaratmadığını" unutmayın (aynı anlama gelir [undefined,undefined,..undefined]). Daha çok "ile aynı uzunluk = 45 ile boş bir dizi oluşturur" ( [undefined x 45]) var foo = []; foo.length=45;. Bu yüzden forEach, ve mapbu durumda geçerli olmayacaktır.
tomalec

1308

ES6'da Array from () ve keys () yöntemlerini kullanarak.

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

Forma operatörü kullanarak daha kısa versiyon .

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

75
Sadece bir not, bu her zaman 0'da başlayacaktır. 1'den başlamak mapiçin değerleri ayarlamak için a'yı diziye zincirlemeniz gerekir[...Array(10).keys()].map(x => x++);
Sterling Archer

32
Sadece değişim map(x => x++)için map(x => ++x)öncelik artıştan dolayı :) değer dönüşü sonra olur
Brock

93
Ne oldu? Neden mapbasitçe yapabiliyorsun slice? [...Array(N+1).keys()].slice(1)
Robin

19
Veya kullanmayın keysve sadece 1 harita ->Array.from(Array(10)).map((e,i)=>i+1)
yonatanmn

60
Veya anahtarları ve haritayı kullanmayın ve sadece bir eşleme işlevini from Array.from(Array(10), (e,i)=>i+1)
iletin

844

Bunu yapabilirsiniz:

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

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

veya rastgele değerlerle:

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

sonuç: [0.7082694901619107, 0.9572225909214467, 0.8586748542729765, 0.8653848143294454, 0.008339877473190427, 0.9911756622605026, 0.8133423360995948, 0.8377588465809822, 0.55775759359511

açıklama

İlk olarak, not Number.call(undefined, N)eşdeğerdir Number(N)hangi sadece getiriler,N . Bu gerçeği daha sonra kullanacağız.

Array.apply(null, [undefined, undefined, undefined])eşdeğerdir Array(undefined, undefined, undefined), üç elemanlı bir dizi oluşturur veundefined her bir öğeye .

Bunu N elementlerine nasıl genelleştirebilirsiniz ? Nasıl Array()çalıştığını düşünün , ki böyle bir şey gider:

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;
}

ECMAScript 5'ten bu yana , Function.prototype.apply(thisArg, argsArray)ördek parametresi olan dizi benzeri bir nesneyi ikinci parametresi olarak kabul eder. Eğer çağırırsak Array.apply(null, { length: N }), o zaman

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

Şimdi her elemanın ayarlanmış bir N- element dizisi var undefined. Onu çağırdığımızda .map(callback, thisArg), her öğe sonucuna ayarlanacaktır callback.call(thisArg, element, index, array). Bu nedenle, [undefined, undefined, …, undefined].map(Number.call, Number)her bir öğeyi daha önce gözlemlediğimiz gibi (Number.call).call(Number, undefined, index, array)aynı olanla Number.call(undefined, index, array)eşler index. Bu, öğeleri dizinleriyle aynı olan diziyi tamamlar.

Neden Array.apply(null, {length: N})sadece yerine beladan geçiyorsun Array(N)? Sonuçta, her iki ifade de tanımsız öğelerden oluşan bir N öğeli diziye neden olur . Fark, önceki ifadede, her öğenin açıkça tanımsız olarak ayarlanmışken , son ifadede her öğenin hiçbir zaman ayarlanmamış olmasıdır. Belgelerine göre .map():

callbackyalnızca atanmış değerleri olan dizinin dizinleri için çağrılır; silinmiş veya hiç değer atanmamış dizinler için çağrılmaz.

Bu nedenle, Array(N)yetersiz; Array(N).map(Number.call, Number)başlatılmamış bir uzunluk N dizisine neden olur .

uygunluk

Bu teknik Function.prototype.apply()ECMAScript 5'te belirtilen davranışa dayandığından, Chrome 14 ve Internet Explorer 9 gibi ECMAScript 5 öncesi tarayıcılarda çalışmaz .



7
Çok zeki - muhtemelen de öyle. Function.prototype.callİlk parametresinin thisdoğrudan Array.prototype.mapyineleyici parametresi üzerinden eşlenecek nesne olduğu gerçeğinden istifade etmek, ona belli bir parlaklığa sahiptir.
Noah Freitas

14
Bu gerçekten, gerçekten zekidir (JS'yi kötüye kullanma sınırları). Buradaki gerçekten önemli içgörü map, benim görüşüme göre , atanmamış değerlerin kendine özgü ifadesidir. Başka bir sürüm (ve muhtemelen biraz daha net, daha uzun da olsa): Array.apply(null, { length: N }).map(function(element, index) { return index; })
Ben Reich

6
@BenReich Daha da iyisi (JS kötüye kullanım düzeyleri açısından): Array.apply(null, new Array(N)).map(function(_,i) { return i; }) veya es6 ve ok işlevleri durumunda, daha da kısa: Array.apply(null, new Array(N)).map((_,i) => i)
oddy

1
Bu 1 ile başlayan bir dizi döndürürse, aslında OP'nin sorusuna cevap verir
Hai Phan

482

ES6'yı Kullanmanın Birden Çok Yolu

Spread operator ( ...) ve keys yöntemini kullanma

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

Dolgu / Harita

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

Array.from

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

Array.from ve { length: N }kesmek

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

Genelleştirilmiş form hakkında not

Değiştirerek hemen hemen arzu edilen herhangi bir değerlere başlatıldı kutu üretmek dizileri üzerindeki tüm formları i+1(örneğin, gerekli ekspresyonuna i*2, -i, 1+i*2, i%2vb). İfade bir işlevle ifade edilebilirse f, ilk form basitçe olur

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

Örnekler:

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

Dizi ile başlatılır yana undefinedher bir pozisyon ile, değeri v olacaktırundefined

Tüm formları gösteren örnek

Özel başlatma işleviyle daha genel bir örnek fyani

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

hatta daha basit

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



5
0'dan başlayan diziler için k ++ kullanın
Borgboy

1
Artırmak istiyorsanız, kullanmayın k++, kullanın ++k.
Alex

4
Poli doldurmadığınız sürece IE'de Array.from desteklenmez.
Lauren

2
TS derleyicisini mutlu etmek için, kullanılmayan parametreyi yerine koymayı düşünün: Array.from ({uzunluk: 5}, (_, k) => k + 1);
Journeycorner

297

Diziler uzunluklarını doğuştan yönetir. Geçildikçe, dizinleri bellekte tutulabilir ve o noktada referans gösterilebilir. Rastgele bir dizinin bilinmesi gerekiyorsa, indexOfyöntem kullanılabilir.


Bu, ihtiyaçlarınız için sadece belirli bir boyutta bir dizi bildirmek isteyebileceğinizi söyledi:

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

Yaymak

Forma operatörünü ( ...) ve keysyöntemi kullanarak, dizinleri oluşturmak için N boyutunda geçici bir dizi oluşturmanıza ve ardından değişkeninize atanabilecek yeni bir dizi oluşturmanıza olanak tanır:

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

Dolgu / Harita

Önce ihtiyacınız olan dizinin boyutunu oluşturabilir, tanımsız olarak doldurabilir ve ardından mapher bir öğeyi dizine ayarlayan yeni bir dizi oluşturabilirsiniz .

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

Array.from

Bu, N boyutunun uzunluğuna başlamalı ve diziyi bir geçişte doldurmalıdır.

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



Yorumlar ve karışıklık yerine, yukarıdaki örneklerde 1.N'deki değerleri gerçekten yakalamak istiyorsanız, birkaç seçenek vardır:

  1. eğer indeks mevcutsa, sadece bir arttırabilirsiniz (örn ++i.).
  2. dizinin kullanılmadığı ve muhtemelen daha etkili bir yol olduğu durumlarda dizinizi oluşturmak, ancak N'yi N + 1'i temsil etmek, sonra önden kaydırmaktır.

    Yani 100 sayı istiyorsanız:

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





Sayı dizisi alıcı sonunda işlenemeyen veriler için kullanıldığında bu yararlı olduğuna inanıyorum. (Yalnızca değerleri değiştiren bir HTML şablonu gibi.)
Neil Monroe

Birisi bunu neden yaparsa, kullanıcıya 1'den 10'a kadar bir seçenek sunan bir açılır liste doldurmak için bir dizi sayıya sahip olmaktır. Elle küçük bir dizi [1,2,3 ... 10] mantıklıdır, ancak 1'den 50'ye mi? Bitiş numarası değişirse ne olur?
CigarDoug

@CigarDoug Bir usecase olduğundan şüphe etmiyorum, ama sanırım küçük. Neden bir sayı dizisine ihtiyaç duyulur, genellikle bir dizi üzerinden yinelenirken, döngü yapısının bir parçası olarak bir döngü kullanılır - döngü gövdesi işlevine bir argüman olarak veya bir sayaç değişkeni - böylece sayı dizisini tutmak önemsiz görünüyor yalnızca belirtilen genişlikte bir dizi oluşturmak veya dizinin üst sınırını tutan bir değişken oluşturmaktır. Birkaç kullanım vakası düşünebilirim, ancak bunların hiçbiri OP
vol7ron

4
Dediğim gibi, 1'den 10'a kadar sayıları içeren bir açılır liste doldurmam gerekiyor. Bir usecase var, benim usecase. Bu sayfayı böyle buldum. Yani elle bir dizi oluşturmak burada gördüğüm her şeyden daha az karmaşıktı. Yani benim ihtiyaçlarım OP'nin gereksinimleri değil. Ama cevabım var.
CigarDoug

1
@ vol7ron Bir usecase var, benim de var. Açısal olarak, disk belleği olarak, altbilgideki tıklanabilir sayfaları göstermek istiyorum. Bu yüzden bir öğedeki öğeleri * ngFor = "let p of PagesCounter" ile döngülüyorum. Bunun için daha iyi bir çözümünüz var mı? BTW, stackoverflow.com/questions/36354325/…
Dalibor

186

ES6'da şunları yapabilirsiniz:

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

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

Düzenleme: Değiştirildi Array(45)için Array(N)soruyu güncelledik beri.

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


3
+1, çünkü büyük bir O kötü .join.splitversiyondan daha iyi - ama yine de mütevazi döngünün daha iyi olduğunu düşünüyorum.
Robin

Katılıyorum @Robin - Algoritmik karmaşıklık bir yana, mütevazi döngü her zaman daha okunabilir. Ancak, Java'daki lambdaların ortaya çıkmasıyla, mapyakında böyle şeyler için bir standart haline geleceğini düşünüyorum .
Nate

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

8
Neden .fill()gerekli olduğunu anlamıyorum . Düğümün repl üzerinde test zaman görüyorum, ama beri Array(1)[0] === undefineddoldurmak için çağrı yapmak ne fark var Array(1).fill(undefined)?
Dominic

11
İlgilenen herkes için, Array (N) ve Array (N) .fill () arasındaki fark burada
Dominic


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

Sonra

var foo = range(1, 5);

Javascript'te bunu yapmanın yerleşik bir yolu yoktur, ancak bir kereden fazla yapmanız gerekirse oluşturmak için mükemmel bir yardımcı program işlevidir.

Düzenleme: Bence, aşağıdaki daha iyi bir aralık işlevidir. Belki sadece LINQ tarafından önyargılı olduğum için, ama daha fazla durumda daha yararlı olduğunu düşünüyorum. Kilometreniz değişebilir.

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

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

2
Bunu severim. Onunla ekstra yol kat etmek isterseniz, Array.prototype.range = function (start, end) {...}; olarak ilan edebilirsiniz. Ardından, herhangi bir Array nesnesindeki aralığı (x, y) çağırabilirsiniz.
Zach Rattner

8
Daha ziyade bir yöntemdir yapmak Arrayyerine Array.prototypeher dizisinde bu yöntemi için hiçbir sebep (hatta oldukça dilsiz düşünülebilecek) olarak orada.
adamse

9
Array.range(1, 5)Muhtemelen daha uygun olurdu, ama yazma konusunda havalı bir şey var [].range(1, 5).
MooGoo

"Aksine Array.prototype yerine Array yöntemi yapın" - Fark nedir? Sadece belirli bir diziyi mi kastediyorsun?
pilau

3
@pilau Tıpkı adamse'ın dediği gibi garip görünüyor. Prototip üzerinde ise söyleyebilirsiniz foo = [1, 2, 3]; bar = foo.range(0, 10);. Ama bu sadece ... kafa karıştırıcı. bar = Array.range(0, 10)çok daha açık ve net. Aralığın örnekle hiçbir ilgisi yoktur, bu nedenle bir örnek yöntemi yapmak için hiçbir neden yoktur.
Ian Henry

53

bir Arrayv8'i doldurmanın en hızlı yolu :

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

sonuç: [0, 1, 2, 3, 4]


ekstra değişken olmadan bunu yapmanın bir yolu var _
bluejayke

@bluejayke no :(
аlex dykyі

sert, .map kaynak kodunun ne olduğunu biliyor musunuz? Bir for döngüsünden daha hızlı olup olmadığından emin değilim, ancak eğer teorik olarak değil, sadece Özellikleri tanımlayabilir ve yeni bir tane yapabiliriz
bluejayke

49

Bu sorunun birçok karmaşık yanıtı var, ancak basit bir tek katlı:

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

Ayrıca, yukarıdakiler yazmak için kısa (ve temiz) olmasına rağmen, aşağıdakilerin biraz daha hızlı olduğunu düşünüyorum (maksimum uzunluk için:

127, Int8,

255, Uint8,

32,767, Int16,

65.535, Uint16,

2.147.483.647, Int32,

4,294,967,295, Uint32.

( maks. tamsayı değerlerine dayalı olarak ), burada da Yazılı Diziler hakkında daha fazla bilgi bulabilirsiniz :

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

Her ne kadar bu çözüm o kadar ideal olmasa da, iki dizi oluşturduğundan ve "$" ekstra değişken bildirimini kullandığından (bu yöntemi kullanarak bu sorunu çözmenin hiçbir yolu olmadığından). Aşağıdaki çözümün bunu yapmanın mümkün olan en hızlı yolu olduğunu düşünüyorum:

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

Bu ifade yapıldıktan sonra, geçerli kapsamda "arr" değişkenini basit bir şekilde kullanabilirsiniz;

Basit bir işlev yapmak istiyorsanız (bazı temel doğrulamalarla):

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
);


böylece, yukarıdaki işlevle, yukarıdaki süper yavaş "basit bir astar" süper hızlı, daha da kısa hale gelir:

range(1,14000);

@JVG ama daha hızlı işlev için değil mi?
bluejayke

Kesinlikle doğru. Herkesin aradığı bu basit tek astar!
supersan

@supersan rağmen süper yavaş :)
bluejayke

Yeni fillyöntemle modern javascript :Array(255).fill(0,0,255)
cacoder

@cacoder ne kadar hızlı, kaç dizi oluşturuyor ve kaç yineleme var?
bluejayke

42

Bunu kullanabilirsiniz:

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

Örneğin

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

şu diziyi oluşturur:

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

Ayrıca, neden olmasın new Array(10).join().split(',').map(function() {return ++arguments[1]});?
Süper

1
@ Bazı durumlar için saltxx, içindeki argümanlarla işlev JS motoru tarafından optimize edilmeyecektir (V8 için bile geçerlidir, bkz. Jsperf.com/arguments-vs-array-argument/2 )
nktssh

4
Bu ilginç bir çözümdür ama tamamen pratik değil - Dizi ayrıştırmak zorunda 3 kez (bir kez için joinbir kez, splitve aslında yapmak istediğim şey için bir kez) sadece güzel değil - Onların gözünden düşmüş görünüyor biliyorum nedense, ama sadece eski moda bir döngü kullanmak çok daha iyi olurdu !
Robin

42

ES6 bu işe yarayacak:

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

sonucu kontrol et:

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


5
aslında, 0..N-1 değil, 1.N istediler
YakovL

1
evet, 1 [...Array(N + 1).keys()].slice(1)getirecek. N
David G

Bazı nedenlerden dolayı bu çözüm, Expo (reat-native) Uygulamasının Üretim Sürümünde çalışmaz. [...Array(N + 1).keys()]bu kod boş bir dizi döndürür, ancak sadece üretim modunda geliştirme modunu kullanarak çalışır.
FabianoLothor

3
.keys()Cevap zaten verildi yıl önce ve 500+ upvotes vardır. Cevabınız buna ne katıyor?
Dan Dascalescu

39

Uygulamanızda d3.js'yi benim gibi kullanıyorsanız , D3 bunu sizin için yapan bir yardımcı işlev sağlar.

Yani 0'dan 4'e kadar bir dizi almak için, bu kadar kolay:

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

ve istediğiniz gibi 1'den 5'e kadar bir dizi almak için:

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

Daha fazla bilgi için bu eğiticiye göz atın .


Bu yorum bana şu anki projemde çalıştığım JS kütüphanesi olan RamdaJS'deki range () işlevini arama fikri verdi . Mükemmel.
Morphatic

39

ES2015 / ES6 forma operatörünü kullanma

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

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


7
i + 1daha mantıklı olurdu ++i.
Vincent Cantin

38

Bu muhtemelen bir dizi sayı oluşturmanın en hızlı yoludur

En kısa

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

Çizgide

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

1'den başlamak istiyorsanız

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]

Bir işlev mi istiyorsunuz?

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]

NEDEN?

  1. while en hızlı döngü

  2. Doğrudan ayar daha hızlı push

  3. [] daha hızlı new Array(10)

  4. kısa ... ilk koda bak. o zaman buradaki diğer tüm işlevlere bakın.

İsterseniz olmadan canlı olamaz için

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

veya

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

8
Bu iddiaları kıstaslarla desteklemek daha iyi olur. Jsperf.com'u deneyin .
Matt Ball

2
lol jsperf ... pls Sadece cevabımı beğenmediniz çünkü diğerleriimi aşağıya düşürmeyi durdurun ... stackoverflow.com/a/18344296/2450730 ... kullanın console.time () ya da nasıl ... jsperf DEĞİL .
cocco

4
Bilginize: John Reisig'in birkaç yıl önce ilk yayınladığı gibi - bazı platformlarda (yani windows: P) her 16ms'de bir kez tarayıcıya besleniyor. Ayrıca, çoklu görev ortamlarında yürütme süresinin ölçülmesiyle ilgili başka sorunlar da vardır. jsperf.com, istatistiksel olarak doğru olmaları için testleri çalıştırmayı uygulamıştır. console.time()Bir sezgi almak için çalıştırın , ancak bir kanıt için jsperf.com'a ihtiyacınız var VE size diğer insanlardan çapraz tarayıcı sonuçlarını gösteriyor (farklı donanım vb.)
naugtur

3
@cocco bu yanlış:var a=[],b=N;while(b--){a[b]=a+1};
vintagexav

5
@ cocco- süre değil , her zaman diğer döngüler daha hızlı. Bazı tarayıcılarda, while döngüsü bir for döngüsünden çok daha yavaştır, javascript performansı hakkında genel ifadeler yapamazsınız çünkü çok farklı optimizasyonlara sahip çok fazla uygulama vardır. Ancak, genel olarak yaklaşımınızı seviyorum. ;-)
RobG

32

doldurmanın yeni yolu Array:

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

sonuç: [0, 1, 2, 3, 4]


Bu gerçekten iyi bir cevap, teknik olarak soru 0- (N-1) değil, 1-N'den olmasına rağmen
bluejayke

31

Eğer lodash kullanıyorsanız, kullanabilirsiniz _.range :

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

Başlangıçtan sona kadar ilerleyen, ancak bitiş içermeyen bir dizi sayı (pozitif ve / veya negatif) oluşturur. Bir bitiş veya adım olmadan negatif bir başlangıç ​​belirtilirse -1 adımı kullanılır. End belirtilmezse, start ile başlayıp 0'a ayarlanır.

Örnekler:

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

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

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

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

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

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

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

30

ES6 ile şunları yapabilirsiniz:

// `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)

Dizinin değerleri aslında bu çözüm kullanılarak doldurulur mapve forEachçalışır.
19:32 de dontmentionthebackup

27

Nihai Özet raporu .. Drrruummm Rolll -

Bu, ES6 kullanmadan N boyutunda (burada 10) bir Array oluşturmak için en kısa koddur . Cocco'nun yukarıdaki sürümü yakın ancak en kısa değil.

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

Ancak bu Kod golfünün tartışmasız kazananı (kaynak kodunun en az baytında belirli bir sorunu çözme yarışması) Niko Ruotsalainen'dir . Array Constructor ve ES6 spread operatörünü kullanma . (ES6 sözdiziminin çoğu geçerli typeScript'tir, ancak aşağıdakiler değildir. Bu yüzden kullanırken dikkatli olun)

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

Neden aşağı oy? Uzun cevap listesini takip etmek zor, bu yüzden özetlemeyi düşündüm.
Şubat'ta sapy

bu 0-10 değil mi? [... Dizi (10) .keys ()]
Greg

Webstorm (yeni Dizi (10)). Tuşlarını () önerir, değil mi?
Guy

(yeni Array (10)). anahtarları (), diziyi değil ArrayIterator {} değerini döndürür
sapy

Bu global bir değişken yaratır a . Döngü olmalıdırfor(var a=[];n--;a[n]=n+1)
kube

20

ES6'da, 2 bağımsız değişken alan Array.from'u kullanan başka bir yol daha var, ilki bir arrayLike (bu durumda özellikli bir nesne length) ve ikincisi bir eşleme işlevidir (bu durumda öğeyi dizinine eşleriz )

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

bu daha kısadır ve çift sayı üretmek gibi diğer diziler için de kullanılabilir

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

Ayrıca bu, diğer birçok yoldan daha iyi bir performansa sahiptir, çünkü dizi boyunca sadece bir kez döngü yapar. Bazı karşılaştırmalar için snippit'i kontrol edin

// 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")


Hey bu temiz, hoşuma gitti. Ancak OP'nin beklediği sonuçları döndürmez. Bunun için şu şekilde yazılması gerekirArray.from({length:N}, (v,i) => i+1)
CervEd

Bu neato kesmek hala iyi bir eski için 5-10x daha yavaştır .
Dan Dascalescu

16

=>ES6 standardından yeni Array yöntemleri ve işlev sözdizimi kullanma (yalnızca yazma sırasında Firefox).

Delikleri aşağıdakilerle doldurarak undefined:

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

Array.fromdönüşler "delikler" içine undefinedöylesine Array.mapbeklendiği gibi çalışır:

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

7
Benzer şekilde, aynı zamanda ES6 içinde aşağıdakileri yapabilirsiniz: Array.from({length: N}, (v, k) => k).
XåpplI'-I0llwlg'I -

Xappli'nin yaklaşımı tercih edilir: Array.from, neredeyse bu senaryo için oluşturuldu ve bir eşleme geri çağrısını ima ediyor. Array yöntemlerini Array.prototype.map.call, örneğin geri döndürülen NodeLists için gibi ayrıntılı yaklaşımlara başvurmadan, dizi benzeri bir şeyde kullanmak istemenin genel sorununa mükemmel bir çözümdür document.querySelectorAll. developer.mozilla.org/tr/docs/Web/JavaScript/Reference/…
Qaribou'dan Josh

Bunu alt çizgi aralığı sözdizimine göre tartıyorum ve aralık daha iyi okuyor.
ooolala

Teknik Array.fromolarak seyrek değerleri tanımsız hale getirmez. Daha ziyade Array(5)seyrek değerleri tanımsız değerler olarak yorumlayan bir argüman nesnesi olarak adlandırılır :)
CervEd



12

ES6'da:

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

ES5:

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

10

Sadece başka bir ES6 sürümü.

Yararlanarak Array.fromikinci opsiyonel argüman:

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

Numaralandırılmış diziyi boş Array(10)konumlardan oluşturabiliriz:

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

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


Bu daha karmaşık ve ~ 10 kat daha yavaş [...Array(11).keys()].slice(1).
Dan Dascalescu

10

Şu anda bu tam cevap listesinde yer almayan tek lezzet, bir jeneratörü içeren bir lezzet gibi görünüyor; bunu düzeltmek için:

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

bu şekilde kullanılabilir:

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

Bununla ilgili güzel bir şey, sadece artırmak zorunda kalmamanız ... @ igor-shubin'in verdiği cevaptan ilham almak için çok kolay bir dizi rastgele oluşturabilirsiniz:

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

Ve operasyonel olarak pahalı uzun bir şey yerine :

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

bunun yerine şunları yapabilirsiniz:

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

10

Es6'dan dizi dolgusu ve harita kullanabilirsiniz; tıpkı bu soru için verdikleri cevaplarda birkaç kişinin önerdiği gibi. Aşağıda birkaç örnek verilmiştir:

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]

Bunu tercih ederim çünkü doğrudan ileri ve daha kolay buluyorum.



9

ES6'yı kullanma

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

Teşekkürler! Bu bence en şık cevaptı! Bir de kullanabilirsiniz Array.from(Array(n))yayılmış operatör desteklenmiyorsa.
Amit

İlk önce neden yayılma işlecini kullanmak zorunda olduğunu bilmiyordum, ama sonra mapMDN hakkında aşağıdakileri okudum : "Dizinin eksik öğeleri (yani, daha önce ayarlanmamış dizinler, silinmiş veya hiç değer atanmamış). "
battmanz

9

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

İade [0, 1, 2]. Igor Shubin'in mükemmel cevabına çok benzer , ancak biraz daha az hile (ve bir karakter daha uzun).

Açıklama:

  • Array(3) // [undefined × 3]N = 3 uzunluğunda bir dizi oluşturun. Ne yazık ki bu dizi bizim için neredeyse işe yaramaz, bu yüzden ...
  • Array.apply(0,Array(3)) // [undefined, undefined, undefined]diziyi yinelenebilir hale getirin. Not: null, uygulamanın ilk argümanı olarak daha yaygındır ancak 0 daha kısadır.
  • Object.keys(Array.apply(0,Array(3))) // ['0', '1', '2'] sonra dizinin anahtarlarını alın (Diziler typeof dizisi olduğu için çalışır, anahtarlar için dizinleri olan bir nesnedir.
  • Object.keys(Array.apply(0,Array(3))).map(Number) // [0, 1, 2] ve dizgileri sayılara dönüştürerek tuşların üzerinden eşleştirin.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.