Python aralığına () benzer JavaScript işlevi


96

JavaScript'te Python'a benzer bir işlev var range()mı?

Bence her seferinde aşağıdaki satırları yazmaktan daha iyi bir yol olmalı:

array = new Array();
for (i = 0; i < specified_len; i++) {
    array[i] = i;
}

1
@clwen: Maalesef yok, ama koduma bir bakın - range()Python'da çalışma şeklini taklit etmeyi amaçlayan bir işlev yazdım , böylece onu kullanabilirsiniz. JavaScript'te böyle bir işlev yoktur, ancak RangeMooTools için sınıf gibi farklı çerçeveler için bazı eklentiler vardır .
Tadeck

Yanıtlar:


89

Hayır , yok ama bir tane yapabilirsin .

JavaScript'in Python'un uygulaması range()

Python'da nasıl çalıştığını taklit etmeye çalışırken, şuna benzer bir işlev yaratırdım:

function range(start, stop, step) {
    if (typeof stop == 'undefined') {
        // one param defined
        stop = start;
        start = 0;
    }

    if (typeof step == 'undefined') {
        step = 1;
    }

    if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
        return [];
    }

    var result = [];
    for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
        result.push(i);
    }

    return result;
};

Bu jsfiddle'a bakın için .

range()JavaScript ve Python arasında karşılaştırma

Şu şekilde çalışır:

  • range(4)döner [0, 1, 2, 3],
  • range(3,6)döner [3, 4, 5],
  • range(0,10,2)döner [0, 2, 4, 6, 8],
  • range(10,0,-1)döner [10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
  • range(8,2,-2)döner [8, 6, 4],
  • range(8,2)döner [],
  • range(8,2,2)döner [],
  • range(1,5,-1)döner [],
  • range(1,5,-2)döner [],

ve Python muadili tam olarak aynı şekilde çalışır (en azından belirtilen durumlarda):

>>> range(4)
[0, 1, 2, 3]
>>> range(3,6)
[3, 4, 5]
>>> range(0,10,2)
[0, 2, 4, 6, 8]
>>> range(10,0,-1)
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> range(8,2,-2)
[8, 6, 4]
>>> range(8,2)
[]
>>> range(8,2,2)
[]
>>> range(1,5,-1)
[]
>>> range(1,5,-2)
[]

Dolayısıyla, Python'a benzer şekilde çalışması için bir işleve ihtiyacınız varsa range(), yukarıda belirtilen çözümü kullanabilirsiniz.


4
belki birkaç ek savunma kontrolü - aktarılan argümanların tümünün sayılara zorlanabileceğinden emin olun ve stopdaha büyük olduğundan emin olun start(ve değilse onları değiştirin).
Russ Cam

1
@RussCam: Bunu belirttiğiniz için teşekkürler. Türler vb. İçin savunma kontrolleri eklemedim, ancak öğelerin ters sırasını uyguladım - şimdi son param negatif tam sayı olduğunda Python muadili ile tamamen aynı şekilde çalışıyor.
Tadeck

@RussCam: start >= stopHedef gerçekten Python'un menzilini taklit ediyorsa, boş bir diziye yönlendirmek gereklidir. Ve yine de daha sezgisel olduğunu iddia ediyorum.

1
@delnan: start >= stopBu işlevin range()Python'daki gibi davranması için basit olması yeterli olmadığından , kontrol daha karmaşık olabilir . Cevabımı güncelledim.
Tadeck

@delnan - Python uygulamasına aşina değilim. Sanırım sadece Python uygulamasına aşina olan kişiler tarafından kullanılacaksa, onu taklit etmenin mantıklı olduğunu düşünüyorum :)
Russ Cam

125

ES6'da çok basit bir aralık için:

let range = n => Array.from(Array(n).keys())

Gönderen bigOmega yorumuyla , bu kullanarak kısaltılabilir Yayılması sözdizimi :

let range = n => [...Array(n).keys()]

41
Bunun daha basit bir versiyonulet range = n => [...Array(n).keys()]
bigOmega

2
@BharathRaja harika, teşekkürler! Neden const değil?
Const'ı elimden

Haklısın, constolabildiğince çok kullanmaya çalışıyorum , ama burada sadece diziye bir referans olacak, bu yüzden dizi yine de düzenlenebilir olacak: 'D
bigOmega

1
@bigOmega İşlevin constdönüş değeri değil, kendisi için geçerli olacaktır. Muhtemelen işlevi hiçbir şekilde değiştirmek istemezsiniz.
Solomon Ucko

7
Bu cevap, bir başlangıç ​​indeksini ve adım boyutunu artırma yeteneğini hesaba katmaz.
Fluous

29

2018: Bu yanıt olumlu oylar almaya devam ediyor, işte bir güncelleme. Aşağıdaki kod eski, ancak neyse ki ES6 standartlaştırılmış oluşturucular ve yieldanahtar kelime ve bunlar evrensel olarak platformlar arasında destekleniyor. Tembel bir örneği range()kullanılarak yieldbulunabilir burada .


Daha önce söylenenlere ek olarak, Javascript 1.7+ yineleyiciler ve oluşturucular için destek sağlar ; bunlar, Python2'ye benzer range, tembel, bellek açısından verimli bir sürüm oluşturmak için kullanılabilir xrange:

function range(low, high) {  
    return {
        __iterator__: function() {
            return {  
                next: function() {
                    if (low > high)
                        throw StopIteration;  
                    return low++;
                }
            }
        }
    }
}

for (var i in range(3, 5))  
  console.log(i); // 3,4,5

1
+1 Harika fikir! Ayrıca uygulamak Could stepargüman ve alınan değerler üzerinde test Cevabıma ? Cevabınız, aklımızda çok özel tarayıcıların olduğu uygulamalar için harika (Google Chrome, Safari ve 9'dan önceki IE sürümlerinde çalışmaz: stackoverflow.com/a/2209743/548696 ).
Tadeck

@Tadeck: İronik bir şekilde, yakın zamanda çok benzer bir soru sordum , kontrol edin - orada bazı iyi cevaplar. BTW, kodunuz testimi geçemiyor; (
georg

Test verilerini ve beklenen sonuçları paylaşır mısınız? İyileştirmekten mutlu olurum, ancak testlerim% 100 başarılı. Verdiğim kodun bu soruya yerleştirdiğiniz komut dosyası tarafından düzgün bir şekilde ayrıştırılmadığını mı söylüyorsunuz: stackoverflow.com/q/12173856/548696 ?
Tadeck

@Tadeck: boşver. Dilimleri test ettim ve kodunuz aralıklar için.
georg

1
Python'un range"son" değeri hariç tutulmuştur (bu nedenle yukarıdaki kod >=yerine kullanılması gerekir >)
Pac0

23

@Tadeck ve @georg'dan gelen iki yanıtı birleştirerek şunu buldum :

function* range(start, stop, step = 1) {
    if (stop == null) {
        // one param defined
        stop = start;
        start = 0;
    }

    for (let i = start; step > 0 ? i < stop : i > stop; i += step) {
        yield i;
    }
}

Bir for döngüsünde kullanmak için ES6 / JS1.7 for-of döngüsüne ihtiyacınız vardır:

for (let i of range(5)) {
    console.log(i);
}
// Outputs => 0 1 2 3 4

for (let i of range(0, 10, 2)) {
    console.log(i);
}
// Outputs => 0 2 4 6 8

for (let i of range(10, 0, -2)) {
    console.log(i);
}
// Outputs => 10 8 6 4 2

ES6 kullanıyorsanız neden varsayılan parametreleri kullanmıyorsunuz?
Amin NAIRI

@Gradiuss bunun için çalışacak stepparametresi, ama ne zaman stop, hem de geçmedi startve stopihtiyaç değiştirilmesi. Güncelleyeceğim
janka102

2
WTG, bu şimdiye kadar sunulan en iyi uygulama. Üreteçleri kullanır (iyi, çünkü tüm diziyi bellekte saklamaya gerek yoktur) ve çok başarılıdır.
Lucio Paiva

tanımsız, null gibi bir nesneye göstericidir. aşağıdaki gibi 3 eşit işaretiyle karşılaştırmak mümkündür: if (stop === undefined) {3 eşittir işaretleri otomatik dönüşüm olmadan karşılaştırılır. aynı zamanda karşılaştırma türü olarak karşılaştırın. 2 eşit işareti, otomatik döküm ile diğer taraf tipiyle karşılaştırılır.
Shimon Doodkin

20

Bir liman rangePython 2'den işlevi tarafından sağlanan underscore.js ve lodash (diğer pek çok yararlı araçlar ile birlikte) yardımcı kütüphaneleri. Alt çizgi belgelerinden kopyalanan örnekler:

_.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]
_.range(0);
=> []

15

NumberPrototipe bir yineleyici eklenerek elde edilebilir

  Number.prototype[Symbol.iterator] = function* () { 
     for (var i = 0; i <= this; i++) {
       yield i
     } 
  }

[...5] // will result in [0,1,2,3,4,5]

Kyle Simpson'ın Rethinking Asynchronous JavaScript kursundan alınmıştır.


7
Bu gerçekten harika, ancak prototipleri geçersiz kılmak çok kırılgan: '(
m0meni

8

Aralığın hem başlangıç ​​hem de bitiş konumunu belirtmeniz gerektiğinde yanıtlardan biri için küçük bir uzantı:

let range = (start, end) => Array.from(Array(end + 1).keys()).slice(start);

7

Hadi bakalım.

Bu, her bir dizinin değerini dizin numarasıyla yazar (veya üzerine yazar).

Array.prototype.writeIndices = function( n ) {
    for( var i = 0; i < (n || this.length); ++i ) this[i] = i;
    return this;
};

Bir sayı sağlamazsanız, Dizinin mevcut uzunluğunu kullanır.

Bunu şu şekilde kullanın:

var array = [].writeIndices(10);  // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

5

Bir dizi boyut elde etmek için x, burada herhangi bir kitaplık kullanmadan tek satırlık bir program var

var range = n => Array(n + 1).join(1).split('').map((x, i) => i)

olarak çalışır

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

2
var range = n => Array(n).fill().map((e, i) => i);
Valen

ve nedenini söylemedi 'boyutu xaslında kullanılan' nparametre adı olarak
Valen

5

Aşağıda Python'un range () işlevinin JavaScript'e doğal bir uyarlaması verilmiştir :

// Generate range from start (inclusive) to stop (exclusive):
function* range(start, stop, step = 1) {
   if (stop === undefined) [start, stop] = [0, start];
   if (step > 0) while (start < stop) yield start, start += step;
   else if (step < 0) while (start > stop) yield start, start += step;
   else throw new RangeError('range() step argument invalid');
} 

// Examples:
console.log([...range(3)]);       // [0, 1, 2]
console.log([...range(0, 3)]);    // [0, 1, 2]
console.log([...range(0, 3, -1)]);// []
console.log([...range(0, 0)]);    // []
console.log([...range(-3)]);      // []
console.log([...range(-3, 0)]);   // [-3, -2, -1]

Bu mukayese edilebilir herhangi bir argüman destekler 0ve stopve ile artırılabilir step. Sayılarla kullanıldığında Python sürümüyle aynı şekilde davranır Number.MAX_SAFE_INTEGER.

Lütfen aşağıdaki köşe durumlarına dikkat edin:

[...range(0, 0, 0)];        // RangeError: range() step argument invalid
[...range(Number.MAX_SAFE_INTEGER + 1, Number.MAX_SAFE_INTEGER + 2)];  // []
[...range(Number.MAX_SAFE_INTEGER + 2, Number.MAX_SAFE_INTEGER + 3)];  // Infinite loop
[...range(0.7, 0.8, 0.1)];  // [0.7, 0.7999999999999999]
[...range('1', '11')];      // ['1']
[...range('2', '22')];      // Infinite loop

Aksine @ Tadeck en , Volv en @ ve @ janka102 en cevabı hangi dönüş [], undefinedveya sonsuz bir döngüye girmek stepdeğerlendirir için 0veya NaNbu jeneratör işlevi Python'un davranışa benzer bir istisna atar.


Kabul. Diğer cevaplar kendilerine göre zarif olsa da, bu yaklaşım ve işlevsellik çok daha pitoniktir.
Travis Clarke

4

ES6 varsayılan parametreleriyle daha da iyileştirildi.

let range = function*(start = 0, stop, step = 1) {
  let cur = (stop === undefined) ? 0 : start;
  let max = (stop === undefined) ? start : stop;
  for (let i = cur; step < 0 ? i > max : i < max; i += step)
    yield i
}

Aralık gerçekten böyle görünmeli.
Konrad Linkowski

4

pythonicPython rangedavranışını en iyi JS 'oluşturucuları ( yield) kullanarak taklit ederek hem range(stop)ve hem de range(start, stop, step)kullanım durumlarını destekler . Buna ek olarak, pythonic'nin rangeişlevi döndüren IteratorPython benzer nesneyi o destekler mapve filtertek tek gömlekleri gibi fantezi yapabileceğini böylece:

import {range} from 'pythonic';
// ...
const results = range(5).map(wouldBeInvokedFiveTimes);
// `results` is now an array containing elements from
// 5 calls to wouldBeInvokedFiveTimes

Şunları kullanarak kurun npm:

npm install --save pythonic

Açıklama Pythonic'in yazarı ve bakımcısıyım


3

MDN şu yaklaşımı önerir: Sıra oluşturucu (aralık)

// Sequence generator function (commonly referred to as "range", e.g. Clojure, PHP etc)
const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));

// Generate numbers range 0..4
console.log("range(0, 4, 1):", range(0, 4, 1));
// [0, 1, 2, 3, 4] 

// Generate numbers range 1..10 with step of 2 
console.log("\nrange(1, 10, 2):", range(1, 10, 2));
// [1, 3, 5, 7, 9]

// Generate the alphabet using Array.from making use of it being ordered as a sequence
console.log("\nrange('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(x => String.fromCharCode(x))", range('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(x => String.fromCharCode(x)));
// ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]


2

Alt çizgi kitaplığını kullanabilirsiniz . Dizilerle çalışmak için düzinelerce kullanışlı işlev ve daha fazlasını içerir.


2

JavaScript'te Python'un range () işlevine benzer bir işlev var mı?

Buradaki tüm çözümler Python 2'nin aralığına atıfta bulunuyor (muhtemelen verdiğiniz kod örneğinden dolayı). Ancak Python 3'te, range () yöntemi bir yineleyici döndürür. JavaScript ayrıca yineleyicilere sahiptir ve tüm diziyi oluşturup bellekte depolamaktan daha fazla alan verimlidir.

Yani Python 3'ün range(n)işlevinin daha doğru temsiliArray(n).keys() .

Örneğin:

for (let i of Array(n).keys()) {
  console.log(i) // 0, 1, 2, 3, ..., n
}

Bir örnek daha (diğer cevaplarda zaten ele alınmıştır). Yineleyiciyi bir diziye dönüştürme (ES6):

let ary = [...Array(n).keys()];
// ary = [0, 1, 2, 3, ..., n]

1

Hala eşdeğer yerleşik bir işlev yok range(), ancak en son sürüm olan ES2015 ile kendi uygulamanızı oluşturabilirsiniz. İşte bunun sınırlı bir versiyonu. Sınırlıdır çünkü adım parametresini hesaba katmaz. Sadece min, maks.

const range = (min = null, max = null) =>
  Array.from({length:max ? max - min : min}, (v,k) => max ? k + min : k)

Bu, Array.frombir lengthözelliği olan herhangi bir nesneden bir dizi oluşturabilen yöntem tarafından gerçekleştirilir . Dolayısıyla, sadece lengthözelliğe sahip basit bir nesnenin aktarılması, bir lengthdizi nesne verecek bir ArrayIterator yaratacaktır .


1

Bu benim tercih ettiğim yol. Python'daki gibi bir veya iki giriş belirlemenize izin verir.

function range(start, end) {
  return Array.from(Array(end||start).keys()).slice(!!end*start)
}

0

İşte aralığın başka bir es6uygulaması

// range :: (from, to, step?) -> [Number]
const range = (from, to, step = 1) => {
  //swap values if necesery
  [from, to] = from > to ? [to, from] : [from, to]
  //create range array
  return [...Array(Math.round((to - from) / step))]
    .map((_, index) => {
      const negative = from < 0 ? Math.abs(from) : 0
      return index < negative ? 
        from + index * step  :
        (index - negative + 1) * step
    })
}  

range(-20, 0, 5)
  .forEach(val => console.log(val))

for(const val of range(5, 1)){
   console.log(`value ${val}`)
}


Biz gelen bir dizi oluşturmak için ne isterseniz -20için -30?
Amin NAIRI

Hmm, bu -30'dan -20'ye kadar bir dizi oluşturacak, ancak isterseniz tersine bir özellik içerecek şekilde kolayca değiştirilebilir. Ben dahil etmeyi yukarıdaki cevabı düzenleyeceksiniz
mrFunkyWisdom

0

Hayır, yok ama bir tane yapabilirsin.

Aralığın Python3 davranışına kısmi. Aşağıda JavaScript'in Python'un aralığı () uygulamasını bulacaksınız:

function* range(start=0, end=undefined, step=1) {    
    if(arguments.length === 1) {end = start, start = 0}    
    
    [...arguments].forEach(arg => {    
        if( typeof arg !== 'number') {throw new TypeError("Invalid argument")}                               
    })    
    if(arguments.length === 0) {throw new TypeError("More arguments neede")}    
        
    if(start >= end) return                                                                                                                                     
    yield start    
    yield* range(start + step, end, step)    
}    
         
// Use Cases
console.log([...range(5)])

console.log([...range(2, 5)])

console.log([...range(2, 5, 2)])
console.log([...range(2,3)])
// You can, of course, iterate through the range instance.


0

Tek adımda basit bir aralığa ihtiyacınız olduğunu varsayarsak:

let range = (start, end)=> {
    if(start === end) return [start];
    return [start, ...range(start + 1, end)];
}

Başka

let range = (start, end, step)=> {
    if(start === end) return [start];
    return [start, ...range(start + step, end)];
}

daha fazlası için buraya bakın .


0

JavaScript'te Python'un range () işlevine benzer bir işlev var mı?

Daha önce cevaplandığı gibi: hayır , yok. Ama kendinizinkini yapabilirsiniz. Bunun ES6 için ilginç bir yaklaşım olduğuna inanıyorum. Python 2.7'ye çok benzer şekilde çalışır range(), ancak çok daha dinamiktir.

function range(start, stop, step = 1) 
{
    // This will make the function behave as range(stop)
    if(arguments.length === 1)
    {
        return [...Array(arguments[0]).keys()]
    }

    // Adjusts step to go towards the stop value
    if((start > stop && !(step < 0)) ||
       (start < stop && !(step > 0)))
    {
        step *= -1
    }

    let returnArray = []
    // Checks if i is in the interval between start and stop no matter if stop
    // is lower than start or vice-versa
    for(let i = start; (i-start)*(i-stop) <= 0; i += step)
    {
        returnArray.push(i)
    }
    return returnArray
}

Bu işlev üç farklı şekilde davranabilir (tıpkı Python'un range () gibi):

  1. range(stop)
  2. range(start, stop)
  3. range(start, stop, step)

Bu örnekler:

console.log(range(5))
console.log(range(-2, 2))
console.log(range(2, -2))
console.log(range(10, 20, 2))

Size aşağıdaki çıktıyı verecektir:

[ 0, 1, 2, 3, 4 ]
[ -2, -1, 0, 1, 2 ]
[ 2, 1, 0, -1, -2 ]
[ 10, 12, 14, 16, 18, 20 ]

inOperatörle (python gibi) dizi üzerinde yineleme yapmak yerine, kullanmanız gerektiğini unutmayın of. Böylece ideğişken, dizinin elemanının dizinini değil değerini varsayar.

for(let i of range(5))
{
    // do something with i...
}

0

NodeJ'ler için bir seçenek, bir Buffer kullanmaktır:

[...Buffer.alloc(5).keys()]
// [ 0, 1, 2, 3, 4 ]

Güzel olan, doğrudan arabellekte yineleyebilmeniz:

Buffer.alloc(5).forEach((_, index) => console.log(index))
// 0
// 1
// 2
// 3
// 4

Bunu başlatılmamış bir Dizi ile yapamazsınız:

Array(5).forEach((_, index) => console.log(index))
// undefined

Ancak, aklı başında böyle bir amaç için Tampon kullanan;)


-1

İşte bunu nasıl yaparım

let n = 5 
[...Array(n).keys()].map(x=>{console.log(x)})

çıktı

0
1
2
3
4

Bu, adımları desteklemez.
Mark Stosberg
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.