Heeft JavaScript een methode zoals “range()” om een bereik binnen de opgegeven grenzen te genereren?

In PHP kun je…

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

Dat wil zeggen, er is een functie waarmee u een reeks cijfers of tekens kunt krijgen door de boven- en ondergrenzen te passeren.

Is hier iets voor ingebouwd in JavaScript? Zo niet, hoe zou ik het dan implementeren?


Antwoord 1, autoriteit 100%

Cijfers

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

Karakteriteratie

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

Iteratie

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"

Als functies

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

Als getypte functies

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()functie

_.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"

Oude niet-es6-browsers zonder bibliotheek:

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

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

Antwoord 2, autoriteit 24%

Voor getallen kunt u ES6 Array.from(), die tegenwoordig in alles werktbehalve IE:

Kortere versie:

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

Langere versie:

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

die een array van 0 tot en met 19 maakt. Dit kan verder worden verkort tot een van deze vormen:

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

Onder- en bovengrenzen kunnen ook worden opgegeven, bijvoorbeeld:

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

Een artikel dat dit in meer detail beschrijft: http://www. 2ality.com/2014/05/es6-array-methods.html


Antwoord 3, autoriteit 9%

Mijn nieuwe favoriete vorm (ES2015)

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

En als je een functie nodig hebt met een stepparameter:

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

Antwoord 4, autoriteit 5%

Hier is mijn 2 cent:

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

Antwoord 5, autoriteit 4%

Het werkt voor tekens en cijfers, vooruit of achteruit gaan met een optionele stap.

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.

Als het vergroten van native typen jouw ding is, wijs het dan toe aan Array.range.


Antwoord 6, autoriteit 3%

Eenvoudige bereikfunctie:

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

Om de bigint gegevenstype bigint Sommige cheque kan worden opgenomen, zodat alle variabelen hetzelfde zijn 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;
}

Om waarden hoger te verwijderen dan gedefinieerd door stopb.v. range(0,5,2)omvat 6, wat niet zou moeten zijn.

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

7, Autoriteit 2%

OK, In Javascript hebben we geen range()Functie zoals PHP , dus we moeten de functie maken die is Heel eenvoudig, ik schrijf een paar één-lijnfuncties voor u en scheid ze voor nummers en alfabetten zoals hieronder:

Voor nummers :

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

en bel het zoals:

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

Voor alfabetten :

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

en noem het als:

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

Antwoord 8, autoriteit 2%

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

Antwoord 9

Handige-functie om de truc uit te voeren, voer het onderstaande codefragment uit

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

Antwoord 10

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

Antwoord 11

— UPDATE (met dank aan @lokhmakov voor de vereenvoudiging) —

Een andere versie die ES6-generatoren gebruikt (zie het geweldige Paolo Moretti-antwoord met ES6-generatoren):

const RANGE = (x,y) => Array.from((function*(){
  while (x <= y) yield x++;
})());
console.log(RANGE(3,7));  // [ 3, 4, 5, 6, 7 ]

Of, als we alleen iterable nodig hebben, dan:

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

— ORIGINELE code was: —

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

en

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

Antwoord 12

Harmony spread-operatoren pijlfuncties gebruiken:

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

Voorbeeld:

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

Antwoord 13

Je kunt lodashof Undescore.jsrange:

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

Als u alleen een opeenvolgend bereik van gehele getallen nodig heeft, kunt u ook zoiets doen als:

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

In ES6 rangekan worden geïmplementeerd met generatoren:

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

Deze implementatie bespaart geheugen bij het herhalen van grote reeksen, omdat het niet alle waarden in een array hoeft te materialiseren:

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

Antwoord 14

Ik heb wat onderzoek gedaan naar verschillende bereikfuncties.
Bekijk de jsperf-vergelijkingvan de verschillende manieren om deze functies uit te voeren. Zeker geen perfecte of uitputtende lijst, maar zou moeten helpen 🙂

De winnaar is…

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

Technisch gezien is het niet de snelste op Firefox, maar het gekke snelheidsverschil (imho) op Chrome maakt het goed.

Ook interessante observatie is hoeveel sneller Chrome is met deze arrayfuncties dan Firefox. Chrome is minstens 4 of 5 keer sneller.


Antwoord 15

Dit is misschien niet de beste manier. Maar als u op zoek bent naar een reeks getallen in een enkele regel code. Bijvoorbeeld 10 – 50

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

Waarbij 40 is (eind – start) en 10 is het begin. Dit zou [10, 11, …, 50]

. moeten opleveren


Antwoord 16

Het standaard Javascript heeft geen ingebouwde functie om bereiken te genereren. Verschillende javascript-frameworks voegen ondersteuning toe voor dergelijke functies, of zoals anderen al hebben opgemerkt, kunt u altijd uw eigen framework gebruiken.

Als u wilt controleren, is de definitieve resource de ECMA-262 standaard .


17

range(start,end,step): met ES6-iterators

U vraagt ​​alleen om een ​​boven- en ondergrenzen. Hier maken we er ook een met een stap.

U kunt eenvoudig range()generatorfunctie maken die kan functioneren als een iterator. Dit betekent dat u niet de volledige array hoeft te genereren.

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

Misschien wilt u mogelijk iets maken dat de array van de iterator genereert en een lijst retourneert. Dit is handig voor functies die een array accepteren. Hiervoor kunnen we Array.from()

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

Nu kunt u eenvoudig een statische array genereren,

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

Maar wanneer iets een iterator wenst (of u de optie geeft om een ​​iterator te gebruiken) kunt u eenvoudig er een maken.

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

Speciale noten


Antwoord 18

Mijn persoonlijke favoriet:

const range = (start, end) => new Array(end-start+1).fill().map((el, ind) => ind + start);

Antwoord 19

Een interessante uitdaging zou zijn om hiervoor de functie kortstete schrijven. Recursie om te redden!

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

Heeft de neiging traag te zijn op grote afstanden, maar gelukkig zijn er kwantumcomputers om de hoek.

Een toegevoegde bonus is dat het verduisterend is. Omdat we allemaal weten hoe belangrijk het is om onze code te verbergen voor nieuwsgierige blikken.

Doe dit om de functie echt en volledig te verdoezelen:

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

Antwoord 20

Ik zou zoiets als dit coderen:

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]

Het gedraagt zich op dezelfde manier als het Python-bereik:

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

Antwoord 21

Een nogal minimalistische implementatie die veel gebruik maakt van ES6 kan als volgt worden gemaakt, met bijzondere aandacht voor de Array.from()statische methode:

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

Antwoord 22

Hoewel dit niet van PHPis, maar een imitatie van rangevan Python.

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] 

Antwoord 23

Deze werkt ook omgekeerd.

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 ]

Antwoord 24

Voor zover ik een numerieke array voor een bepaald bereik genereer, gebruik ik dit:

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]

Het werkt duidelijk niet voor alfabetische arrays.


Antwoord 25

Je kunt de volgende one-liner gebruiken om het kort en simpel te houden

var start = 4;
var end = 20;
console.log(Array(end - start + 1).fill(start).map((x, y) => x + y));

Antwoord 26

Nog niet geïmplementeerd!

Met behulp van het nieuwe Number.rangevoorstel(fase 1):

[...Number.range(1, 10)]
//=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Antwoord 27

Gebruik dit. Het creëert een array met een bepaald aantal waarden (niet gedefinieerd), in het volgende voorbeeld zijn er 100 indexen, maar het is niet relevant omdat je hier alleen de sleutels nodig hebt. Het gebruikt in de array 100 + 1, omdat de arrays altijd op index 0 zijn gebaseerd. Dus als het 100 waarden heeft gekregen om te genereren, begint de index vanaf 0; daarom is de laatste waarde altijd 99, niet 100.

range(2, 100);
function range(start, end) {
    console.log([...Array(end + 1).keys()].filter(value => end >= value && start <= value ));
}

Antwoord 28

D3 heeft ook een ingebouwde bereikfunctie. Zie https://github.com/mbostock/d3/wiki/arrays#d3_range:

D3.Range ([Start,] Stop [, stap])

genereert een array met een rekenkundige progressie, vergelijkbaar met het ingebouwde Python-bereik. Deze methode wordt vaak gebruikt om te herhalen over een reeks van numerieke of gehele getalwaarden, zoals de indexen in een array. In tegenstelling tot de Python-versie zijn de argumenten niet verplicht om gehele getallen te zijn, hoewel de resultaten voorspelbaarder zijn als ze te wijten zijn aan drijvende punt precisie. Als stap is weggelaten, is het standaard van 1.

Voorbeeld:

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

29

met Harmony generatoren , ondersteund door alle browsers behalve IE11 :

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

Voorbeelden

nemen

Voorbeeld 1.

takeneemt slechts zoveel als het kan

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

retourneert

[100, 105, 110, 115, 120]

Voorbeeld 2.

toniet nodig

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

retouren

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

takeAll

Voorbeeld 3.

fromniet nodig

takeAll( range( {to: 5} ) )

retouren

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

Voorbeeld 4.

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

retouren

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

Voorbeeld 5.

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

retourneert

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

Other episodes