web-dev-qa-db-fra.com

Fonction JavaScript similaire à la gamme Python ()

Existe-t-il une fonction en JavaScript similaire à la fonction range() de Python?

Je pense qu'il devrait y avoir un meilleur moyen que d'écrire les lignes suivantes à chaque fois:

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

Non, il n'y en a pas, mais vous pouvez en créer un.

Implémentation JavaScript de la range() de Python

En essayant de émuler comment cela fonctionne en Python, je créerais une fonction similaire à celle-ci:

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

Voir ce jsfiddle pour une preuve.

Comparaison entre range() en JavaScript et Python

Cela fonctionne de la manière suivante:

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

et son homologue Python fonctionne exactement de la même manière (au moins dans les cas mentionnés):

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

Donc, si vous avez besoin d’une fonction qui fonctionne de la même manière que la fonction range() de Python, vous pouvez utiliser la solution susmentionnée.

69
Tadeck

Pour une gamme très simple dans ES6:

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

2018: cette réponse ne cesse de recevoir des votes, voici donc une mise à jour. Le code ci-dessous est obsolète, mais heureusement, les générateurs standardisés ES6 et le mot clé yield sont universellement pris en charge sur toutes les plates-formes. Un exemple de range() paresseux utilisant yield peut être trouvé ici


En plus de ce qui a déjà été dit, Javascript 1.7+ prend en charge les itérateurs et les générateurs qui peuvent être utilisés pour créer une version paresseuse et économe en mémoire de range, similaire à xrange en 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
25
georg

Un port de la fonction range de Python est fourni par les bibliothèques d’utilitaires underscore.js et lodash (avec de nombreux autres outils utiles). Exemples copiés à partir des documents de soulignement:

_.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
Mark Amery

En fusionnant les deux réponses de @Tadeck et @georg , j'ai trouvé ceci

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

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

Pour l'utiliser dans une boucle for, vous avez besoin de la boucle for-of de ES6/JS1.7:

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

Peut être obtenu en attachant un itérateur au prototype 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]

Extrait du cours de Kyle Simpson Repenser le JavaScript asynchrone

12
mcha

Voici.

Ceci écrira (ou écrasera) la valeur de chaque index avec le numéro d'index.

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

Si vous ne fournissez pas de numéro, il utilisera la longueur actuelle du tableau.

Utilisez-le comme ceci:

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

Pour obtenir un tableau de taille x, voici un one-liner sans utiliser aucune bibliothèque

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

travailler en tant que 

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

Voici une petite extension pour l'une des réponses au cas où vous auriez besoin de spécifier les positions de début et de fin de la plage:

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

Ce qui suit est une adaptation naturelle de la fonction range () de Python à 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]

Il supporte tous les arguments qui peuvent être comparés à 0 et stop et peuvent être incrémentés de step. Il se comporte de manière identique à la version Python lorsqu'il est utilisé avec des nombres ne dépassant pas Number.MAX_SAFE_INTEGER.

Veuillez noter les cas suivants:

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

Contrairement à @ Tadeck's , @ Volv's et @ janka102's answer qui renvoie [], undefined ou entre une boucle infinie lorsque step est évalué à 0 ou NaN, cette fonction de générateur génère une exception similaire Le comportement de Python.

4
le_m

Raffiné davantage avec les paramètres par défaut de l’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
}
3
Volv

Vous pouvez utiliser underscore library. Il contient des dizaines de fonctions utiles pour travailler avec des tableaux et bien d’autres.

2
Radagast

MDN recommande cette approche: Générateur de séquence (plage)

0
IliasT

Non, il n'y en a pas, mais vous pouvez en créer un.

Je suis partial au comportement de gamme de Python3. Vous trouverez ci-dessous l'implémentation par JavaScript de la gamme de Python ():

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
elayira

Pythonic imite le comportement Python range de la meilleure façon possible en utilisant les générateurs de JS (yield), prenant en charge les cas d'utilisation range(stop) et range(start, stop, step). De plus, la fonction Pythonic de range renvoie un objet Generator construit sur mesure qui prend en charge map et filter, de sorte que vous pouvez utiliser des lignes simples telles que:

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

Installez en utilisant npm:

npm install --save Pythonic

Voici le code dans Pythonic pour range:

function range(...args) {
    if (args.length < 2) {
        return new Generator(rangeGeneratorWithStop(...args));
    }
    return new Generator(rangeGeneratorWithSartAndStopAndStep(...args));
}

const rangeGeneratorWithStop = stop => function * () {
    for (let i = 0; i < stop; i++) {
        yield i;
    }
};

const rangeGeneratorWithSartAndStopAndStep = (start, stop, step = 1) => function * () {
    for (let i = start; i < stop; i += step) {
        yield i;
    }
};

function range(...args) {
    if (args.length < 2) {
        return new Generator(rangeGeneratorWithStop(...args));
    }
    return new Generator(rangeGeneratorWithSartAndStopAndStep(...args));
}

class Generator {
    constructor(generatorFn) {
        this[Symbol.iterator] = generatorFn;
    }

    map(callbackFn) {
        const result = [];
        for (const element of this) {
            result.Push(callbackFn(element));
        }
        return result;
    }

    filter(callbackFn) {
        const result = [];
        for (const element of this) {
            if (callbackFn(element)) {
                result.Push(element);
            }
        }
        return result;
    }

    toArray() {
        return Array.from(this);
    }
}
0
Keyvan

Voici une autre implémentation es6 de la plage 

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

0
mrFunkyWisdom