Pythonのrange()に似たJavaScript関数


103

Pythonに似たJavaScriptの関数はありrange()ますか?

毎回次の行を書くよりも良い方法があるはずだと思います。

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

1
@clwen:残念ながらありませんが、私のコードを見てください-Pythonでのrange()動作をエミュレートすることを目的とした関数を作成したので、それを使用できます。JavaScriptにはそのような関数はありませんがRange、MooToolsのクラスなど、さまざまなフレームワーク用のプラグインがいくつかあります。
タデック2011年

回答:


92

いいえ、ありませんが作成できます

JavaScriptによるPythonの実装 range()

Pythonどのように機能するかエミュレートしようとすると、次のような関数を作成します。

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

証拠については、このjsfiddleを参照してください。

range()JavaScriptとPythonの比較

これは次のように機能します。

  • 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)を返します[]

そしてそれに対応するPythonはまったく同じように機能します(少なくとも前述の場合):

>>> 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)
[]

したがって、Pythonと同様に機能する関数が必要なrange()場合は、上記のソリューションを使用できます。


4
おそらく、いくつかの追加の防御チェック-渡された引数がすべて数値に対して強制可能であることを確認し、それstopがより大きいことを確認しますstart(そうでない場合はそれらを交換します)。
ラスカム

1
@RussCam:これを指摘してくれてありがとう。型などの防御チェックを追加しませんでしたが、要素の逆順を実装しました。最後のパラメーターが負の整数の場合、Pythonの対応するものとまったく同じように機能するようになりました。
タデック2011年

@RussCam:start >= stop目標が実際にPythonの範囲をエミュレートすることである場合は、空の配列に導く必要があります。とにかくもっと直感的だと思います。

1
@delnan:start >= stopこの関数range()がPythonのように動作するには単純では不十分であるため、チェックはより複雑になる可能性があります。回答を更新しました。
タデック2011年

@ delnan-私はPythonの実装に精通していません。Pythonの実装に精通している覗き見でのみ使用されるのであれば、それをエミュレートするのが理にかなっていると思います:)
Russ Cam

130

ES6の非常に単純な範囲の場合:

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

bigOmegaのコメントから、これはSpread構文を使用して短縮できます

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

41
これのより単純なバージョンはlet range = n => [...Array(n).keys()]
bigOmega 2017

2
@BharathRaja素晴らしい、ありがとう!なぜconstしないのですか?可能な限りconstを使用しようとします:)Javaの最終的な対応物のように;)
Kjellski 2018年

そうです、私constは可能な限り使用しようとしますが、ここでは配列への参照にすぎないため、配列は引き続き編集可能です: 'D
bigOmega

1
@bigOmegaconstは、戻り値ではなく、関数自体に適用されます。おそらく、関数を変更したくないでしょう。
ソロモンウッコ

7
この回答は、開始インデックスとステップサイズを増やす機能を考慮していません。
流暢な

31

2018:この回答は賛成票を集め続けているので、ここに更新があります。以下のコードは廃止されましたが、幸いなことにES6で標準化されたジェネレーターとyieldキーワードであり、プラットフォーム間で広くサポートされています。怠け者の例range()使用をyield見つけることができるここに


すでにJavascriptの1.7以降がサポートを提供、言っているものに加えてイテレータとジェネレータの怠惰、メモリ効率の高いバージョンを作成するために使用することができrangeにsimlar、xrange:Python2での

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素晴らしいアイデア!step引数も実装して、私の答えの値でテストできますか?あなたの答えは、私たちが非常に特定のブラウザを念頭に置いているアプリケーションに最適です(9より前のバージョンのGoogle Chrome、Safari、IEでは機能しません:stackoverflow.com/a/2209743/548696)。
タデック2012

@Tadeck:皮肉なことに、私は最近非常によく似た質問をしました。それをチェックしてください-そこにいくつかの良い答えがあります。ところで、あなたのコードは私のテストに合格しません;(
georg 2012

テストデータと期待される結果を共有できますか?私はそれを改善したいと思いますが、私のテストは100%合格です。私が与えたコードは、この質問に配置したスクリプトによって適切に解析されていないと言っていますか:stackoverflow.com/q/12173856/548696
タデック2012

@Tadeck:気にしないでください。スライスをテストしましたが、コードは範囲用です。
georg 2012

1
Pythonのrange「最後の」値は除外されています(したがって、上記のコードの>=代わりに使用する必要が>あります)
Pac0 2010

24

@Tadeck@georgからの両方の回答を融合して、私はこれを思いついた:

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

forループで使用するには、ES6 /JS1.7のfor-ofループが必要です。

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を使用している場合、デフォルトのパラメータを使用しないのはなぜですか?
アミンナイリ2017

それがために働くだろう@Gradiussstepパラメータが、ときstopに渡されていない、両方startstop変更する必要があります。更新します
janka102 2017年

2
WTG、これはこれまでに提示された最良の実装です。ジェネレーターを使用し(シーケンス全体をメモリに格納する必要がないため、優れています)、非常に簡潔です。
Lucio Paiva 2017年

undefinedは、nullのようなオブジェクトへのポインタです。次のような3つの等号と比較できます:if(stop === undefined){3つの等号は自動キャストなしで比較されます。比較タイプもそのまま比較します。2つの等号は、他のサイドタイプへの自動鋳造と比較されます。
Shimon Doodkin 2018年

21

rangePython 2の関数の移植版は、underscore.jsおよびlodashユーティリティライブラリ(および他の多くの便利なツール)によって提供されます。アンダースコアドキュメントからコピーされた例:

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

16

Numberプロトタイプにイテレータを取り付けることで実現できます

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

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

カイルシンプソンのコース「非同期JavaScriptの再考」からの抜粋


8
これは本当にクールですが、プロトタイプをオーバーライドするのは非常に壊れやすいです: '(
m0meni 2017年

9

範囲の開始位置と終了位置の両方を指定する必要がある場合に備えて、回答の1つを少し拡張したものを次に示します。

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

7

どうぞ。

これにより、各インデックスの値がインデックス番号で書き込まれます(または上書きされます)。

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

数値を指定しない場合は、配列の現在の長さが使用されます。

次のように使用します。

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

5

ES6のデフォルトパラメータでさらに洗練されています。

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
}

これは、範囲が実際にどのように見えるかです。
KonradLinkowski20年

5

サイズの配列を取得するために、xライブラリを使用せずにワンライナーを使用します

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

として動作します

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

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

そして、x実際にnパラメータ名として使用したときに「サイズ」と言う理由
Valen

5

以下は、Pythonのrange()関数をJavaScriptに自然に適応させたものです。

// 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]

これは、と比較することができ、任意の引数をサポート0し、stopかつずつ増加することができますがstep。を超えない数で使用すると、Pythonバージョンと同じように動作しますNumber.MAX_SAFE_INTEGER

次のコーナーケースに注意してください。

[...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

対照的に、@ TadeckさんVOLVの@@ janka102の答えはこれリターン[]undefinedまたは時に無限ループに入るstep評価さに0NaN、この生成関数はPythonの行動のような例外がスローされます。


同意しました。他の答えは独自の方法でエレガントですが、このアプローチと機能ははるかにPython的です。
トラヴィス・クラーク

4

pythonicrangeJSのジェネレーター(yield)を使用してPythonの動作を最もよく模倣し、range(stop)range(start, stop, step)ユースケースの両方をサポートします。また、pythonicrange関数が返すIteratorサポートしているのPythonに似たオブジェクトをmapしてfilter:1のような空想のワンライナーを行うことができますので、

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

を使用してインストールnpm

npm install --save pythonic

開示私はPythonicの作成者およびメンテナーです


3

MDNはこのアプローチを推奨しています:シーケンスジェネレーター(範囲)

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

Pythonのrange()に似たJavaScriptの関数はありますか?

ここでのすべてのソリューションは、Python 2の範囲を参照しています(おそらく、提供したコード例が原因です)。ただし、Python 3では、range()メソッドはイテレータを返します。JavaScriptにもイテレータがあり、配列全体を生成してメモリに格納するよりもスペース効率が高くなります。

したがって、Python3のrange(n)関数のより正確な表現はですArray(n).keys()

例えば:

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

もう1つの例(他の回答ですでに説明されています)。イテレータを配列に変換する(ES6):

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

1

と同等の組み込み関数はまだありませんrange()が、最新バージョンであるES2015を使用すると、独自の実装を構築できます。これが限定版です。ステップパラメータが考慮されていないため、制限されています。最小、最大

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

これはArray.fromlengthプロパティを持つ任意のオブジェクトから配列を構築できるメソッドによって実現されます。したがって、lengthプロパティのみを含む単純なオブジェクトを渡すと、オブジェクトのlength数を生成するArrayIteratorが作成されます。


1

これが私の好みの方法です。Pythonのように1つまたは2つの入力を指定できます。

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

0

これes6が範囲の別の実装です

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


から-20への配列を生成したい場合はどうなり-30ますか?
アミンナイリ

うーん、これは-30から-20までの配列を生成しますが、必要に応じて、reverseプロパティを含めるように簡単に変更できます。私はそれを含めて上記の答えを編集します
mrFunkyWisdom

0

いいえ、ありませんが、作成できます。

私は範囲のPython3の振る舞いに部分的です。以下に、JavaScriptによるPythonのrange()の実装を示します。

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

単一のステップで単純な範囲が必要であると仮定します。

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

そうしないと

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

詳細については、こちらを参照しください。


0

Pythonのrange()に似たJavaScriptの関数はありますか?

前に答えたように:いいえ、ありません。しかし、あなたはあなた自身のものを作ることができます。これはES6にとって興味深いアプローチだと思います。Python 2.7range()と非常によく似ていますが、はるかに動的です。

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
}

この関数は、3つの異なる方法で動作できます(Pythonのrange()のように)。

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

これらの例:

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

次の出力が得られます。

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

in演算子(Pythonなど)を使用して配列を反復処理する代わりに、を使用する必要があることに注意してくださいof。したがって、i変数は配列の要素のインデックスではなく値を想定します。

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

0

NodeJのオプションは、バッファーを使用することです。

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

良い点は、バッファーで直接反復できることです。

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

初期化されていない配列ではそれを行うことはできません。

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

しかし、彼らの正しい心の中で誰がこのような目的のためにバッファを使用します;)


0
function range(start, stop) {
    if (typeof stop == 'undefined') {
        stop = start;
        start = 0;
    }
   
    result = [...Array(stop).keys()].slice(start, stop);
    return result;
}

-1

これが私がそれをする方法です

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

出力

0
1
2
3
4

これは手順をサポートしていません。
MarkStosberg20年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.