JavaScript'in, sağlanan sınırlar dahilinde bir aralık oluşturmak için “range ()” gibi bir yöntemi var mı?


871

PHP'de şunları yapabilirsiniz ...

range(1, 3); // Array(1, 2, 3)
range("A", "C"); // Array("A", "B", "C")

Yani, üst ve alt sınırları geçerek bir dizi sayı veya karakter elde etmenizi sağlayan bir işlev vardır.

Bunun için yerel olarak JavaScript'te yerleşik bir şey var mı? Değilse, nasıl uygularım?


1
Prototype.js $Rişlevi vardır, ancak bunun dışında gerçekten sanmıyorum.
Yi Jiang

Bu (ilgili) sorunun bazı mükemmel cevapları var: stackoverflow.com/questions/6299500/…
btk

Array.from("ABC") //['A', 'B', 'C']Sorunun ikinci kısmı için bulabildiğim en yakın şey bu.
Andrew_1510

@ Andrew_1510 split("")Orada da kullanabilirsiniz
alex

1
Lover bağlı bu oneliner sıfır olduğunda:Array.apply(null, { length: 10 }).map(eval.call, Number)
csharpfolk

Yanıtlar:


1499

sayılar

[...Array(5).keys()];
 => [0, 1, 2, 3, 4]

Karakter yinelemesi

String.fromCharCode(...[...Array('D'.charCodeAt(0) - 'A'.charCodeAt(0) + 1).keys()].map(i => i + 'A'.charCodeAt(0)));
 => "ABCD"

tekrarlama

for (const x of Array(5).keys()) {
  console.log(x, String.fromCharCode('A'.charCodeAt(0) + x));
}
 => 0,"A" 1,"B" 2,"C" 3,"D" 4,"E"

Fonksiyonlar olarak

function range(size, startAt = 0) {
    return [...Array(size).keys()].map(i => i + startAt);
}

function characterRange(startChar, endChar) {
    return String.fromCharCode(...range(endChar.charCodeAt(0) -
            startChar.charCodeAt(0), startChar.charCodeAt(0)))
}

Yazılan fonksiyonlar gibi

function range(size:number, startAt:number = 0):ReadonlyArray<number> {
    return [...Array(size).keys()].map(i => i + startAt);
}

function characterRange(startChar:string, endChar:string):ReadonlyArray<string> {
    return String.fromCharCode(...range(endChar.charCodeAt(0) -
            startChar.charCodeAt(0), startChar.charCodeAt(0)))
}

lodash.js _.range()işlevi

_.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]
String.fromCharCode(..._.range('A'.charCodeAt(0), 'D'.charCodeAt(0) + 1));
 => "ABCD"

Kitaplık içermeyen eski es6 olmayan tarayıcılar:

Array.apply(null, Array(5)).map(function (_, i) {return i;});
 => [0, 1, 2, 3, 4]

console.log([...Array(5).keys()]);

(Nils petersohn ve diğer yorumculara ES6 kredisi)


72
Çünkü herhangi bir yerde faydalıysa, muhtemelen JS'de yararlıdır. (JS, bir aralıktan faydalanabilecek işlevsel programlama türü şeyler yapabilir (0 deyimi. Bu ve diğer bazı nedenler bazı semirare durumlarında yararlı olabilir)
Lodewijk

5
Neden sadece kullanmanın (new Array(5)).map(function (value, index) { return index; })işe yaramadığı hakkında bir fikrin var mı? Bu [undefined × 5]benim için Chrome DevTools'ta geri dönüyor.
Lewis,

12
@Lewis Çünkü bununla tanımlanan bir dizi , veya arkadaşlarından biriyle yinelenmeyecek boş yuvalara sahip map().
alex

65
Array.from (Dizi (5) .keys ())
nils petersohn

17
Array(5).fill()aynı zamanda mappable
nils petersohn

333

Sayılar için Array.from(), bu günlerde her şeyde çalışan ES6'yı kullanabilirsiniz IE hariç :

Kısa versiyon:

Array.from({length: 20}, (x,i) => i);

Daha uzun versiyon:

Array.from(new Array(20), (x,i) => i)

0 ile 19 arasında bir dizi oluşturur. Bu, aşağıdaki formlardan birine daha da kısaltılabilir:

Array.from(Array(20).keys())
// or
[...Array(20).keys()]

Alt ve üst sınırlar da belirtilebilir, örneğin:

Array.from(new Array(20), (x,i) => i + *lowerBound*)

Bunu daha ayrıntılı olarak açıklayan bir makale: http://www.2ality.com/2014/05/es6-array-methods.html


50
İlk örnek bile basitleştirilebilir [... Array (20) .keys ()]
Delapouite

27
Metottan biraz daha özlü Array.from()ve her ikisinden de daha hızlı:Array(20).fill().map((_, i) => i)
Stu Cox

2
@Delapouite Harika! Bunu ayrı bir cevap vermelisin, ben de oy vereceğim! Aynı zamanda bu kopyaya mükemmel bir cevap .
pergel

9
@Delapouite @jib Ve bu da:Array.from({length: end - start}, (v, k) => k + start)
Aditya Singh

1
@ icc97 Evet, linters şikayet edebilir, ancak JavaScript'te geçmeyle aynı olarak tanımlanan bir işlev bağımsız değişkenini atlamak undefined, bu nedenle fill()(bağımsız değişken olmadan) kendiliğinden yanlış değildir. Dolgu değeri bu çözümde kullanılmaz, bu nedenle isterseniz fill(0)birkaç karakter kaydetmek için kullanabilirsiniz .
Stu Cox

122

Yeni favori formum ( ES2015 )

Array(10).fill(1).map((x, y) => x + y)

Ve eğer bir stepparametreyle bir işleve ihtiyacınız varsa :

const range = (start, stop, step = 1) =>
  Array(Math.ceil((stop - start) / step)).fill(start).map((x, y) => x + y * step)

5
let range = (start, stop, step = 1) => Dizi (durdur - başlat). dolgu (başlat) .map ((x, y) => x + y * adım)
rodfersou 2'de

4
@rodfersou FYI: örneğiniz yanlış. stopaslında durma / bitiş konumu değil, sayım / uzaklıktır. (suç yok, sadece insanları yazım hatası hakkında bilgilendirmek için)
F Lekschas

4
Şaşkın için - rodfersou'nun F Lekschas'ın yorumundan sonra düzenlemesi nedeniyle, kodu şimdi doğru.
eedrah

1
Eğer geçmek argüman Array(Math.ceil((stop - start) / step) + 1), ihtiyacı +1gerçekten mimik php'nin "dahil" davranışına, sonunda.
Johan Dettmar

3
Bu, bir rangeyöntemi tam olarak uygulayan bir Javascript işlevinin tam sorusunu yanıtlayan en iyi yanıttır . Şu anda bunun üzerindeki tüm diğerleri (lodash'lar hariç _.range) start, stop ve step ile gerçek bir aralık işlevi yerine temel yineleyicileri uygular
icc97

99

İşte 2 sentim:

function range(start, count) {
  return Array.apply(0, Array(count))
    .map((element, index) => index + start);
}

1
Yüksek dereceli fonksiyonların mükemmel kullanımı.
Farzad YZ

5
Bu aslında yanlış çünkü soru başlangıç ​​ve bitiş değerleri istiyor. Başlangıç ​​ve sayım / mesafe değil.
James Robey

73

Karakterler ve sayılar için çalışır, isteğe bağlı bir adımla ileri veya geri gider.

var range = function(start, end, step) {
    var range = [];
    var typeofStart = typeof start;
    var typeofEnd = typeof end;

    if (step === 0) {
        throw TypeError("Step cannot be zero.");
    }

    if (typeofStart == "undefined" || typeofEnd == "undefined") {
        throw TypeError("Must pass start and end arguments.");
    } else if (typeofStart != typeofEnd) {
        throw TypeError("Start and end arguments must be of same type.");
    }

    typeof step == "undefined" && (step = 1);

    if (end < start) {
        step = -step;
    }

    if (typeofStart == "number") {

        while (step > 0 ? end >= start : end <= start) {
            range.push(start);
            start += step;
        }

    } else if (typeofStart == "string") {

        if (start.length != 1 || end.length != 1) {
            throw TypeError("Only strings with one character are supported.");
        }

        start = start.charCodeAt(0);
        end = end.charCodeAt(0);

        while (step > 0 ? end >= start : end <= start) {
            range.push(String.fromCharCode(start));
            start += step;
        }

    } else {
        throw TypeError("Only string and number types are supported");
    }

    return range;

}

jsFiddle .

Yerel türleri artırmak sizin işinizse, atayın Array.range.


53

Basit aralık işlevi:

function range(start, stop, step) {
    var a = [start], b = start;
    while (b < stop) {
        a.push(b += step || 1);
    }
    return a;
}

Dahil etmek BitInt veri türü tüm değişkenler aynı olmasını sağlayarak, bazı çek dahil edilebilir typeof start:

function range(start, stop, step) {
    var a = [start], b = start;
    if (typeof start == 'bigint') {
        stop = BigInt(stop)
        step = step? BigInt(step): 1n;
    } else
        step = step || 1;
    while (b < stop) {
        a.push(b += step);
    }
    return a;
}

stopÖrneğin tarafından belirtilenden daha yüksek değerleri kaldırmak için range(0,5,2)içermesi 6gerekir.

function range(start, stop, step) {
    var a = [start], b = start;
    while (b < stop) {
        a.push(b += step || 1);
    }
    return (b > stop) ? a.slice(0,-1) : a;
}

3
PLUS UNO kullanılabilir ve okunabilir. Uzun zamandır gördüğüm en iyi kod snippet'i.
monsto

1
Bu zaman çalışmaz step != 1, whiledurum alması gereken stepdikkate. Varsayılan stepdeğere sahip güncellenmiş sürümüm : işlev aralığı (başlat, durdur, adım) {step = step || 1 var a = [başlat], b = başlat; while ((b + adım) <durdur) {console.log ("b:" + b + ". a:" + a + "."); b * = aşaması; a.push (b) } dönüş a; }
daveharris

@daveharris Yukarıda varsayılan bir adım ekledim (step || 1).
Bay Polywhirl

36
Array.range= function(a, b, step){
    var A= [];
    if(typeof a== 'number'){
        A[0]= a;
        step= step || 1;
        while(a+step<= b){
            A[A.length]= a+= step;
        }
    }
    else{
        var s= 'abcdefghijklmnopqrstuvwxyz';
        if(a=== a.toUpperCase()){
            b=b.toUpperCase();
            s= s.toUpperCase();
        }
        s= s.substring(s.indexOf(a), s.indexOf(b)+ 1);
        A= s.split('');        
    }
    return A;
}


    Array.range(0,10);
    // [0,1,2,3,4,5,6,7,8,9,10]

    Array.range(-100,100,20);
    // [-100,-80,-60,-40,-20,0,20,40,60,80,100]

    Array.range('A','F');
    // ['A','B','C','D','E','F')

    Array.range('m','r');
    // ['m','n','o','p','q','r']

ArrayPrototip üzerinde gerçekten jerry-rig yöntemleri kullanmamalısınız .
connectyourcharger

Bu yöntem yalnızca tamsayılar ve karakterlerle çalışır. Parametreleri null, tanımsız ise, NaN, boolean, dizi, nesne, vb, bu yöntem aşağıdaki hata verir: undefined method toUpperCase to etc!
Victor

`` if (typeof from! == 'sayı' && typeof from! == 'string') {yeni new TypeError atın ('İlk parametre bir sayı veya karakter olmalı')} if (typeof to! == ' numarası '&& typeof to! ==' string ') {yeni TypeError atın (' İlk parametre bir sayı veya karakter olmalı ')} ``
Victor

36

Tamam, JavaScript'te PHPrange() gibi bir fonksiyonumuz yok , bu yüzden oldukça kolay bir şey yaratmamız gerekiyor, sizin için tek satırlık birkaç fonksiyon yazıyorum ve bunları Sayılar ve Alfabeler için aşağıdaki gibi ayırıyorum :

için Numaraları :

function numberRange (start, end) {
  return new Array(end - start).fill().map((d, i) => i + start);
}

ve şöyle deyin:

numberRange(5, 10); //[5, 6, 7, 8, 9]

için alfabeler :

function alphabetRange (start, end) {
  return new Array(end.charCodeAt(0) - start.charCodeAt(0)).fill().map((d, i) => String.fromCharCode(i + start.charCodeAt(0)));
}

ve şöyle deyin:

alphabetRange('c', 'h'); //["c", "d", "e", "f", "g"]

2
Bu işlevlerde tek tek hatalar olduğunu düşünüyorum. Olmalı Array(end - start + 1)ve Array(end.charCodeAt(0) - start.charCodeAt(0) + 1).
earcanal

24

Hile yapmak için kullanışlı işlev, aşağıdaki kod snippet'ini çalıştırın

function range(start, end, step, offset) {
  
  var len = (Math.abs(end - start) + ((offset || 0) * 2)) / (step || 1) + 1;
  var direction = start < end ? 1 : -1;
  var startingPoint = start - (direction * (offset || 0));
  var stepSize = direction * (step || 1);
  
  return Array(len).fill(0).map(function(_, index) {
    return startingPoint + (stepSize * index);
  });
  
}

console.log('range(1, 5)=> ' + range(1, 5));
console.log('range(5, 1)=> ' + range(5, 1));
console.log('range(5, 5)=> ' + range(5, 5));
console.log('range(-5, 5)=> ' + range(-5, 5));
console.log('range(-10, 5, 5)=> ' + range(-10, 5, 5));
console.log('range(1, 5, 1, 2)=> ' + range(1, 5, 1, 2));

İşte nasıl kullanılır

aralık (Başlangıç, Bitiş, Adım = 1, Ofset = 0);

  • kapsayıcı - ileri range(5,10) // [5, 6, 7, 8, 9, 10]
  • herşey dahil - geri range(10,5) // [10, 9, 8, 7, 6, 5]
  • geri adım range(10,2,2) // [10, 8, 6, 4, 2]
  • özel - ileri range(5,10,0,-1) // [6, 7, 8, 9] not 5,10 themselves
  • ofset - genişlet range(5,10,0,1) // [4, 5, 6, 7, 8, 9, 10, 11]
  • ofset - küçült range(5,10,0,-2) // [7, 8]
  • adım genişlet range(10,0,2,2) // [12, 10, 8, 6, 4, 2, 0, -2]

Umarım faydalı bulursunuz.


Ve işte böyle çalışır.

Temelde ilk olarak ortaya çıkan dizinin uzunluğunu hesaplıyorum ve bu uzunlukta sıfır dolu bir dizi oluşturuyorum, sonra gerekli değerlerle dolduruyorum

  • (step || 1)=> Ve bu yollarla gibi başkaları değerini kullanmak stepve kullanımını sağlanmadı ise 1yerine
  • Daha (Math.abs(end - start) + ((offset || 0) * 2)) / (step || 1) + 1)basit hale getirmek için sonuç dizisinin uzunluğunu hesaplayarak başlıyoruz (her iki yönde / adımda fark * ofseti)
  • Uzunluğu aldıktan sonra, burada kontrol kullanarak başlatılmış değerlerle boş bir dizi oluştururuznew Array(length).fill(0);
  • Şimdi [0,0,0,..]istediğimiz uzunlukta bir dizimiz var . Üzerinde harita oluşturup, ihtiyacımız olan değerleri kullanarak yeni bir dizi döndürüyoruzArray.map(function() {})
  • var direction = start < end ? 1 : 0;Açıkçası eğer bizden startdaha küçük değilse endgeriye doğru gitmemiz gerekir. Yani 0'dan 5'e gitmek ya da tam tersi
  • Her yinelemede, startingPoint+ stepSize* indexirade bize ihtiyacımız olan değeri verir

8
Kesinlikle, kesinlikle. Basit? Naçizane size katılmıyorum; ne olursa olsun onu tek bir astar haline getirirsiniz. Python'dan gelen bu bir şok.
PascalVKooten

@PascalvKooten, evet tabii ki python gibi yerleşik bir yöntem olsaydı harika olurdu, ama bu gelebileceğim en basitiydi. Ve projelerimde kullanışlı olduğu kanıtlandı.
azerafati

Özellikle tek katmanlı olarak ve nasıl çalıştığına dair bir açıklama olmadan böyle ağrılı bir kod pasajı göndermek? "Çalışıyor" olsun ya da olmasın iyi bir SO cevabının zayıf örneği .
Madbreaks

1
@Madbreaks, evet haklısın. Tek astar yapmak için saf oldum. herkese hızlı ve kolay bir çözüm sunmak istedim
azerafati

22
var range = (l,r) => new Array(r - l).fill().map((_,k) => k + l);

@nikkwong, _eşleme geri aramasında yalnızca bir argüman adıdır. Bilirsiniz, bazı dillerde _değişkenin kullanılmadığını göstermek için bir ad olarak kullanırsınız.
Klesun

Ancak burada _, argümanlarından geçmedi range. Neden olmasın?
nikk wong

2
Çok temiz! Bununla birlikte, herhangi bir IE veya Opera'da çalışmadığını not etmek önemlidir.
Rafael Xavier

4
Bu cevabın açıklanması gerekiyor, çünkü SO için zayıf bir uyum.
Madbreaks

@RafaelXavier IE üzerinde Array.fill () polyfill
mwag

18

Harmony yayma operatörü ve ok işlevlerini kullanma:

var range = (start, end) => [...Array(end - start + 1)].map((_, i) => start + i);

Misal:

range(10, 15);
[ 10, 11, 12, 13, 14, 15 ]

bu en iyi cevap!
Henry H.

1
En hızlı değil.
mjwrazor

Bu durumda alt çizgi '_' sembolü neyi temsil eder?
Oleh Berehovskyi

@OlehBerehovskyi Aslında kullanmak niyetiniz olmayan bir lambda fonksiyon parametresi anlamına gelir. Kullanılmayan değişkenler hakkında uyaran bir linter bunu göz ardı etmelidir.
Micah Zoltu

18

--- GÜNCELLEME (Sadeleştirme için @lokhmakov'a teşekkürler) ---

ES6 jeneratörlerini kullanan başka bir sürüm (ES6 jeneratörleriyle harika Paolo Moretti cevabına bakın ):

const RANGE = (x,y) => Array.from((function*(){
  while (x <= y) yield x++;
})());

console.log(RANGE(3,7));  // [ 3, 4, 5, 6, 7 ]

Ya da, sadece tekrarlanabilirliğe ihtiyacımız olursa, o zaman:

const RANGE_ITER = (x,y) => (function*(){
  while (x <= y) yield x++;
})();

for (let n of RANGE_ITER(3,7)){
  console.log(n);
}

// 3
// 4
// 5
// 6
// 7

--- ORGINAL kodu: ---

const RANGE = (a,b) => Array.from((function*(x,y){
  while (x <= y) yield x++;
})(a,b));

ve

const RANGE_ITER = (a,b) => (function*(x,y){
  while (x <= y) yield x++;
})(a,b);

1
Just const range = (x, y) => Array.from(function* () { while (x <= y) yield x++; }())
lokhmakov

@lokhmakov Evet, haklısın. teşekkür ederim! Kodumu cevabımda uyguladım.
Hero Qu

15

Çeşitli Menzil Fonksiyonları üzerine biraz araştırma yaptı. Bu fonksiyonları yapmak için farklı yollar jsperf karşılaştırmasını kontrol edin. Kesinlikle mükemmel veya kapsamlı bir liste değil, ama yardımcı olmalı :)

Kazanan...

function range(lowEnd,highEnd){
    var arr = [],
    c = highEnd - lowEnd + 1;
    while ( c-- ) {
        arr[c] = highEnd--
    }
    return arr;
}
range(0,31);

Teknik olarak firefox'ta en hızlı değil, ancak kromdaki çılgın hız farkı (imho) bunu telafi ediyor.

Ayrıca ilginç gözlem, bu dizi işlevlerinde kromun firefox'tan ne kadar hızlı olduğu. Chrome en az 4 veya 5 kat daha hızlı .


Bunun bir adım boyutu parametresi içeren aralık işlevleriyle karşılaştırıldığını unutmayın
binaryfunt

15

Standart Javascript'te aralık oluşturmak için yerleşik bir işlev yoktur. Birkaç javascript çerçevesi bu tür özellikler için destek ekler veya diğerlerinin işaret ettiği gibi her zaman kendinize ait olabilirsiniz.

Tekrar kontrol etmek isterseniz, kesin kaynak ECMA-262 Standardıdır .


2010'da mükemmel bir cevap olduğundan emin olmamla birlikte, bu artık en iyi yaklaşım olarak görülmemelidir. Prototype.js gibi yerleşik türleri genişletmemelisiniz 👍
Dana Woodman

@DanaWoodman bunu getirdiğin için teşekkürler - Prototype.js'ye yapılan referansı çıkarmak için cevabı güncelledim, çünkü bu gerçekten 2018'de çok eski
Mike Dinescu

21
Bu hiç yardımcı olmadı.
Pithikos

@Pithikos Bu sorunun başlangıçta sorulduğu ve OP'nin JS'de bir yerel aralık işlevi olup olmadığını bilmek istediği için düzenlendiğini görüyorum.
Mike Dinescu

13

Lodash veya Undescore.js'yi kullanabilirsiniz range:

var range = require('lodash/range')
range(10)
// -> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

Alternatif olarak, yalnızca ardışık bir tamsayı aralığına ihtiyacınız varsa aşağıdaki gibi bir şey yapabilirsiniz:

Array.apply(undefined, { length: 10 }).map(Number.call, Number)
// -> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

ES6'da jeneratörlerrange ile uygulanabilir :

function* range(start=0, end=null, step=1) {
  if (end == null) {
    end = start;
    start = 0;
  }

  for (let i=start; i < end; i+=step) {
    yield i;
  }
}

Bu uygulama, büyük dizileri yinelerken bellek tasarrufu sağlar, çünkü tüm değerleri bir dizide gerçekleştirmek zorunda değildir:

for (let i of range(1, oneZillion)) {
  console.log(i);
}

ES6 kısmı şimdi bu sorunun doğru cevabıdır. Diğer cevaplarla kapsanan diğer kısımları çıkarmanızı tavsiye ederim.
15'te joews

jeneratörler bir döngü dışında kullanılırsa biraz gariptir: x = aralık (1, 10); // {} x; // {} // boş bir harita gibi görünüyor WTF!?! x.next (). value; // OK 1; x [3] // undefined, sadece gerçek dizi ile
Anona112

@ Anona112, Array.fromjeneratörleri dizi örneklerine dönüştürmek ve çıktıyı incelemek için kullanabilirsiniz.
Paolo Moretti

10

İlginç bir zorluk, bunu yapmak için en kısa fonksiyonu yazmak olacaktır . Kurtarmaya özyineleme!

function r(a,b){return a>b?[]:[a].concat(r(++a,b))}

Geniş aralıklarda yavaş olma eğilimindedir, ancak neyse ki kuantum bilgisayarlar hemen köşede.

Ek bir avantaj, gizemli olmasıdır. Çünkü kodumuzu meraklı gözlerden saklamanın ne kadar önemli olduğunu hepimiz biliyoruz.

İşlevi tamamen ve tamamen gizlemek için şunu yapın:

function r(a,b){return (a<b?[a,b].concat(r(++a,--b)):a>b?[]:[a]).sort(function(a,b){return a-b})}

4
Kısa! = Basit, ama daha basit daha iyidir. İşte okunması daha kolay bir sürüm: const range = (a, b) => (a>=b) ? [] : [a, ...range(a+1, b)]ES6 sözdizimini kullanarak
nafg

1
@nafg: const range = (a, b, Δ = 1) => (a > b) ? [] : [a, ...range(a + Δ, b, Δ)];. Ayrıca yorum için tüm cevabı iptal.
7vujy0f0hy

10

Bu en iyi yol olmayabilir. Ancak tek bir kod satırında bir dizi sayı almak istiyorsanız. Örneğin 10-50

Array(40).fill(undefined).map((n, i) => i + 10)

Burada 40 (bitiş - başlangıç) ve 10 başlangıçtır. Bu geri dönmelidir [10, 11, ..., 50]


9

Ben böyle bir şey kodlamak istiyorum:

function range(start, end) {
    return Array(end-start).join(0).split(0).map(function(val, id) {return id+start});
}  

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

range(3,9);
// [3,4,5,6,7,8]

Python serisine benzer şekilde davranır:

>>> range(-4,2)
[-4, -3, -2, -1, 0, 1]

8

ES6'yı yoğun şekilde kullanan oldukça minimalist bir uygulama, Array.from()statik yönteme özellikle dikkat çekerek aşağıdaki gibi oluşturulabilir :

const getRange = (start, stop) => Array.from(
  new Array((stop - start) + 1),
  (_, i) => i + start
);

Bir yan not olarak, bir getRange()çeşit "gelişmiş" işlev yaptığım bir Gist oluşturdum . Özellikle, yukarıdaki çıplak kemik varyantında adressiz olabilecek son vakaları yakalamayı amaçladım. Ayrıca, alfasayısal aralıklar için destek ekledim. Diğer bir deyişle, 'C've 'K'(bu sırayla) gibi iki getRange('C', 'K'); // => ["C", "D", "E", "F", "G", "H", "I", "J"]
girişle çağrıldığında

newanahtar kelimeye ihtiyacınız yok
Soldeplata Saketos

8

range(start,end,step): ES6 Yineleyiciler ile

Sadece üst ve alt sınırlar istersiniz. Burada da bir adımla bir tane oluşturuyoruz.

range()Bir yineleyici olarak işlev görebilen jeneratör işlevini kolayca oluşturabilirsiniz . Bu, dizinin tamamını önceden oluşturmanız gerekmediği anlamına gelir.

function * range ( start, end, step = 1 ) {
  let state = start;
  while ( state < end ) {
    yield state;
    state += step;
  }
  return;
};

Şimdi diziyi yineleyiciden önceden oluşturan ve bir liste döndüren bir şey oluşturmak isteyebilirsiniz. Bu, bir diziyi kabul eden işlevler için kullanışlıdır. Bunun için kullanabilirizArray.from()

const generate_array = (start,end,step) =>
  Array.from( range(start,end,step) );

Artık kolayca statik bir dizi oluşturabilirsiniz,

const array1 = generate_array(1,10,2);
const array1 = generate_array(1,7);

Ancak bir şey bir yineleyici istediğinde (veya size bir yineleyici kullanma seçeneği verdiğinde) kolayca bir tane oluşturabilirsiniz.

for ( const i of range(1, Number.MAX_SAFE_INTEGER, 7) ) {
  console.log(i)
}

Özel notlar


7

Bu PHP'den değil range, Python'dan bir taklit .

function range(start, end) {
    var total = [];

    if (!end) {
        end = start;
        start = 0;
    }

    for (var i = start; i < end; i += 1) {
        total.push(i);
    }

    return total;
}

console.log(range(10)); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
console.log(range(0, 10)); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(range(5, 10)); // [5, 6, 7, 8, 9] 

En hızlı için +1. -36768 - 36768 bir dizi ile 3ms aldı, 2.lik 13 ms ve IDE kırmızı çizgiler var.
mjwrazor

7

Belirli bir aralık için sayısal bir dizi oluşturma kadar ben bunu kullanın:

function range(start, stop)
{
    var array = [];

    var length = stop - start; 

    for (var i = 0; i <= length; i++) { 
        array[i] = start;
        start++;
    }

    return array;
}

console.log(range(1, 7));  // [1,2,3,4,5,6,7]
console.log(range(5, 10)); // [5,6,7,8,9,10]
console.log(range(-2, 3)); // [-2,-1,0,1,2,3]

Açıkçası, alfabetik diziler için işe yaramaz.


array = []Döngünün içindeki ayar size istediğinizi vermeyebilir.
alex

@alex, teşekkür ederim. Haklısın, ayrıca döngünün her geçişinde "start" parametresini artırmayı unuttum. Şimdi düzeltildi.
jhaskell

Hala istenen çıktıyı üretmeyecek, eğer 5-10 aralığı istersem, bana verecek [5, 6, 7, 8, 9, 10, 11, 12, 13, 14], bu dizinin sadece ilk yarısını beklerdim.
alex

@alex, tekrar teşekkür ederim, girdiye dayalı bir uzunluk kısıtlaması düşünmemiştim. Güncellenmiş sürüme bakın.
jhaskell

6

Kullanılması Harmony jeneratörler , IE11 dışındaki tüm tarayıcılar tarafından desteklenen :

var take = function (amount, generator) {
    var a = [];

    try {
        while (amount) {
            a.push(generator.next());
            amount -= 1;
        }
    } catch (e) {}

    return a;
};

var takeAll = function (gen) {
    var a = [],
        x;

    try {
        do {
            x = a.push(gen.next());
        } while (x);
    } catch (e) {}

    return a;
};

var range = (function (d) {
    var unlimited = (typeof d.to === "undefined");

    if (typeof d.from === "undefined") {
        d.from = 0;
    }

    if (typeof d.step === "undefined") {
        if (unlimited) {
            d.step = 1;
        }
    } else {
        if (typeof d.from !== "string") {
            if (d.from < d.to) {
                d.step = 1;
            } else {
                d.step = -1;
            }
        } else {
            if (d.from.charCodeAt(0) < d.to.charCodeAt(0)) {
                d.step = 1;
            } else {
                d.step = -1;
            }
        }
    }

    if (typeof d.from === "string") {
        for (let i = d.from.charCodeAt(0); (d.step > 0) ? (unlimited ? true : i <= d.to.charCodeAt(0)) : (i >= d.to.charCodeAt(0)); i += d.step) {
            yield String.fromCharCode(i);
        }
    } else {
        for (let i = d.from; (d.step > 0) ? (unlimited ? true : i <= d.to) : (i >= d.to); i += d.step) {
            yield i;
        }
    }
});

Örnekler

almak

Örnek 1.

take sadece alabildiği kadar sürer

take(10, range( {from: 100, step: 5, to: 120} ) )

İadeler

[100, 105, 110, 115, 120]

Örnek 2.

to gerekli değil

take(10, range( {from: 100, step: 5} ) )

İadeler

[100, 105, 110, 115, 120, 125, 130, 135, 140, 145]

hepsini al

Örnek 3.

from gerekli değil

takeAll( range( {to: 5} ) )

İadeler

[0, 1, 2, 3, 4, 5]

Örnek 4.

takeAll( range( {to: 500, step: 100} ) )

İadeler

[0, 100, 200, 300, 400, 500]

Örnek 5.

takeAll( range( {from: 'z', to: 'a'} ) )

İadeler

["z", "y", "x", "w", "v", "u", "t", "s", "r", "q", "p", "o", "n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b", "a"]


Önerilerimle düzenlendi :)
Xotic750

+1 yaklaşım için. @ Alex'in noktasına göre, formaddede üçlü işlemlerin (özellikle iç içe olmayan) olmaması, burada okunabilirliği artıracaktır.
Justin Johnson

5

... bir jeneratör fonksiyonu kullanarak daha fazla menzil.

function range(s, e, str){
  // create generator that handles numbers & strings.
  function *gen(s, e, str){
    while(s <= e){
      yield (!str) ? s : str[s]
      s++
    }
  }
  if (typeof s === 'string' && !str)
    str = 'abcdefghijklmnopqrstuvwxyz'
  const from = (!str) ? s : str.indexOf(s)
  const to = (!str) ? e : str.indexOf(e)
  // use the generator and return.
  return [...gen(from, to, str)]
}

// usage ...
console.log(range('l', 'w'))
//=> [ 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w' ]

console.log(range(7, 12))
//=> [ 7, 8, 9, 10, 11, 12 ]

// first 'o' to first 't' of passed in string.
console.log(range('o', 't', "ssshhhooooouuut!!!!"))
// => [ 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 't' ]

// only lowercase args allowed here, but ...
console.log(range('m', 'v').map(v=>v.toUpperCase()))
//=> [ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V' ]

// => and decreasing range ...
console.log(range('m', 'v').map(v=>v.toUpperCase()).reverse())

// => ... and with a step
console.log(range('m', 'v')
          .map(v=>v.toUpperCase())
          .reverse()
          .reduce((acc, c, i) => (i % 2) ? acc.concat(c) : acc, []))

// ... etc, etc.

Umarım faydalıdır.


5

Codegolfing iş arkadaşım bu (ES6) dahil, geldi:

(s,f)=>[...Array(f-s+1)].map((e,i)=>i+s)

içermeyen:

(s,f)=>[...Array(f-s)].map((e,i)=>i+s)


4

d3 ayrıca dahili bir menzil fonksiyonuna sahiptir. Bkz. Https://github.com/mbostock/d3/wiki/Arrays#d3_range :

d3.range ([başlat;] durdur [, adım])

Python yerleşik aralığına benzer şekilde aritmetik bir ilerleme içeren bir dizi oluşturur. Bu yöntem genellikle dizinler gibi bir dizi sayısal veya tamsayı değer dizisini yinelemek için kullanılır. Python sürümünden farklı olarak, değişkenlerin tamsayı olması gerekmez, ancak sonuçlar kayan nokta hassasiyetinden kaynaklanıyorsa daha tahmin edilebilir. Adım atlanırsa, varsayılan olarak 1 olur.

Misal:

d3.range(10)
// returns [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

D3'ün var olduğunu hiç bilmiyordum. Range yöntemini kullanmayacak, ancak bu paketi kullanacaktır.
mjwrazor

Çok teşekkür ederim. Ben D3 kullanın ve ben bir D3 zaten sunuyor bilmeden, yerel bir JS yöntemi arıyordu.
cezar

4

Range ([start,] stop [, step]) imzasını kullanarak ES6 uygulamasını tamamlayın:

function range(start, stop, step=1){
  if(!stop){stop=start;start=0;}
  return Array.from(new Array(int((stop-start)/step)), (x,i) => start+ i*step)
}

Otomatik negatif adım istiyorsanız,

if(stop<start)step=-Math.abs(step)

Veya daha minimalist olarak:

range=(b, e, step=1)=>{
  if(!e){e=b;b=0}
  return Array.from(new Array(int((e-b)/step)), (_,i) => b<e? b+i*step : b-i*step)
}

Büyük aralıklarınız varsa Paolo Moretti'nin jeneratör yaklaşımına bakın


Değiştir !stopile typeof stop === 'undefined', daha sonra değiştirmek intile Math.floorve bir çek eklemek if (start > stop && step > 0)(aksi takdirde, range(-3, -10)yerine ya adımın işareti saygısız veya dönen (bir şey SANE yapmanın bir istisna atar [])). Aksi takdirde, iyi!
Ahmed Fasih

4

Bunun için bir npm modülü var ("bereich" Almanca "aralık" kelimesidir). Modern JavaScript yineleyicilerinden yararlanır, böylece aşağıdakiler gibi çeşitli şekillerde kullanabilirsiniz:

console.log(...bereich(1, 10));
// => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

const numbers = Array.from(bereich(1, 10));
// => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

for (const number of bereich(1, 10)) {
  // ...
}

Ayrıca azalan aralıkları da destekler (sadece değiş tokuş yaparak minve max) ve ayrıca dışındaki adımları da destekler 1.

Feragatname: Bu modülün yazarıyım, bu yüzden lütfen cevabımı bir tuz tanesi ile alın.


4

Bu da ters yönde çalışır.

const range = ( a , b ) => Array.from( new Array( b > a ? b - a : a - b ), ( x, i ) => b > a ? i + a : a - i );

range( -3, 2 ); // [ -3, -2, -1, 0, 1 ]
range( 1, -4 ); // [ 1, 0, -1, -2, -3 ]
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.