Apakah JavaScript memiliki metode seperti "rentang ()" untuk menghasilkan rentang dalam batas yang disediakan?

873

Di PHP, Anda bisa melakukan ...

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

Artinya, ada fungsi yang memungkinkan Anda mendapatkan rentang angka atau karakter dengan melewati batas atas dan bawah.

Apakah ada bawaan untuk JavaScript untuk ini? Jika tidak, bagaimana saya menerapkannya?

alex
sumber
1
Prototype.js memiliki $Rfungsi, tetapi selain itu saya tidak berpikir begitu.
Yi Jiang
Pertanyaan (terkait) ini memiliki beberapa jawaban luar biasa: stackoverflow.com/questions/6299500/…
btk
Array.from("ABC") //['A', 'B', 'C']Ini adalah hal terdekat yang dapat saya temukan untuk bagian kedua dari pertanyaan.
Andrew_1510
@ Andrew_1510 Anda bisa menggunakannya di split("")sana juga
alex
1
Ketika kekasih terikat adalah nol pada penumpang ini:Array.apply(null, { length: 10 }).map(eval.call, Number)
csharpfolk

Jawaban:

1502

Angka

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

Iterasi karakter

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

Pengulangan

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"

Sebagai fungsi

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

Seperti fungsi yang diketik

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

_.range()fungsi lodash.js

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

Peramban non es6 lama tanpa perpustakaan:

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

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

(Kredit ES6 untuk nils petersohn dan komentator lainnya)

Ben
sumber
72
Karena jika itu berguna di mana saja itu mungkin berguna di JS. (JS dapat melakukan hal-hal jenis pemrograman fungsional, yang dapat mengambil manfaat dari kisaran (pernyataan 0. Itu dan seribu alasan lain mungkin berguna dalam beberapa kasus semirare)
Lodewijk
5
Adakah ide mengapa hanya menggunakan (new Array(5)).map(function (value, index) { return index; })tidak akan berhasil? Ini kembali [undefined × 5]untuk saya di Chrome DevTools.
Lewis
12
@Lewis Karena array yang didefinisikan dengan yang memiliki slot kosong yang tidak akan diulangi dengan map()atau salah satu temannya.
alex
65
Array.from (Array (5) .key ())
nils petersohn
17
Array(5).fill()juga dapat dipetakan
nils petersohn
333

Untuk angka, Anda dapat menggunakan ES6 Array.from(), yang berfungsi dalam segala hal saat ini kecuali IE:

Versi lebih pendek:

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

Versi yang lebih panjang:

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

yang menciptakan array dari 0 hingga 19 inklusif. Ini dapat disingkat menjadi salah satu dari bentuk-bentuk ini:

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

Batas bawah dan atas dapat ditentukan juga, misalnya:

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

Artikel yang menjelaskan hal ini secara lebih rinci: http://www.2ality.com/2014/05/es6-array-methods.html

Kristjan Liiva
sumber
50
Contoh pertama bahkan dapat disederhanakan menjadi [... Array (20) .key ()]
Delapouite
27
Sedikit lebih ringkas daripada Array.from()metodenya, dan lebih cepat dari keduanya:Array(20).fill().map((_, i) => i)
Stu Cox
2
@Delapouite Luar Biasa! Anda harus membuat jawaban yang terpisah, dan saya akan memilihnya! Ini juga jawaban sempurna untuk duplikat ini .
jib
9
@Delapouite @jib Dan ini juga:Array.from({length: end - start}, (v, k) => k + start)
Aditya Singh
1
@ icc97 Ya, linter mungkin mengeluh, meskipun dalam JavaScript menghilangkan argumen fungsi yang didefinisikan sama dengan passing undefined, jadi fill()(tanpa argumen) tidak salah per se. Nilai isian tidak digunakan dalam solusi itu, jadi jika Anda suka, Anda bisa menggunakan fill(0)untuk menyimpan beberapa karakter.
Stu Cox
122

Formulir favorit baru saya ( ES2015 )

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

Dan jika Anda membutuhkan fungsi dengan stepparam:

const range = (start, stop, step = 1) =>
  Array(Math.ceil((stop - start) / step)).fill(start).map((x, y) => x + y * step)
Kutyel
sumber
5
biarkan range = (mulai, berhenti, langkah = 1) => Array (stop - start) .fill (start) .map ((x, y) => x + y * langkah)
rodfersou
4
@rodfersou FYI: contoh Anda salah. stopsebenarnya bukan posisi berhenti / ujung tetapi menghitung / jarak. (jangan tersinggung, hanya untuk membuat orang sadar akan kesalahan ketik)
F Lekschas
4
Untuk yang bingung - karena edit rodfersou setelah komentar F Lekschas, kodenya sekarang benar.
eedrah
1
Argumen yang Anda sampaikan Array(Math.ceil((stop - start) / step) + 1), perlu +1di bagian akhir, untuk benar-benar meniru perilaku "inklusif" php.
Johan Dettmar
3
Ini adalah jawaban teratas yang benar-benar menjawab pertanyaan lengkap dari fungsi Javascript yang sepenuhnya mengimplementasikan rangemetode. Semua yang lain saat ini di atas ini (kecuali untuk lodash's _.range) menerapkan iterator dasar daripada fungsi rentang yang sebenarnya dengan start, stop dan step
icc97
99

Inilah 2 sen saya:

function range(start, count) {
  return Array.apply(0, Array(count))
    .map((element, index) => index + start);
}
jflood.net
sumber
1
Penggunaan fungsi orde tinggi yang luar biasa.
Farzad YZ
5
Ini sebenarnya salah karena pertanyaannya adalah meminta nilai awal & akhir. Tidak memulai & menghitung / jarak.
James Robey
73

Ini berfungsi untuk karakter dan angka, maju atau mundur dengan langkah opsional.

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 .

Jika menambah tipe asli adalah hal Anda, maka tetapkan untuk itu Array.range.

alex
sumber
53

Fungsi rentang sederhana:

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

Untuk memasukkan tipe data BitInt beberapa pemeriksaan dapat dimasukkan, memastikan bahwa semua variabel sama 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;
}

Untuk menghapus nilai yang lebih tinggi dari yang didefinisikan oleh stopmisalnya range(0,5,2)akan termasuk 6, yang seharusnya tidak.

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;
}
Remi
sumber
3
PLUS UNO untuk dapat digunakan dan dibaca. Cuplikan kode terbaik yang pernah saya lihat dalam waktu yang lama.
monsto
1
Ini tidak berfungsi ketika step != 1, whilekondisi perlu stepdiperhitungkan. Versi saya yang diperbarui dengan stepnilai default : rentang fungsi (mulai, berhenti, langkah) {step = step || 1 var a = [mulai], b = mulai; while ((b + step) <stop) {console.log ("b:" + b + ". a:" + a + "."); b + = langkah; a.push (b); } mengembalikan a; }
daveharris
@daveharris Saya menambahkan langkah standar di atas (step || 1),.
Tn. 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']
kennebec
sumber
Anda benar-benar tidak boleh metode jerry-rig ke Arrayprototipe.
Hubungkan chargerAnda
Metode ini hanya bekerja dengan bilangan bulat dan karakter. Jika parameter null, terdefinisi, NaN, boolean, array, objek, dll, metode ini mengembalikan kesalahan berikut: undefined method toUpperCase to etc!
Victor
`` `if (typeof from! == 'number' && typeof from! == 'string') {throw TypeError baru ('Parameter pertama harus berupa angka atau karakter')} if (typeof to! == ' number '&& typeof to! ==' string ') {throw TypeError baru (' Parameter pertama harus berupa angka atau karakter ')} `` `
Victor
36

OK, di JavaScript kami tidak memiliki range()fungsi seperti PHP , jadi kami perlu membuat fungsi yang cukup mudah, saya menulis beberapa fungsi satu-baris untuk Anda dan memisahkannya untuk Bilangan dan Abjad seperti di bawah ini:

untuk Angka :

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

dan menyebutnya seperti:

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

untuk Abjad :

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

dan menyebutnya seperti:

alphabetRange('c', 'h'); //["c", "d", "e", "f", "g"]
Alireza
sumber
2
Saya pikir ada kesalahan satu-persatu dalam fungsi-fungsi ini. Seharusnya Array(end - start + 1), dan Array(end.charCodeAt(0) - start.charCodeAt(0) + 1).
earcanal
24

Berguna untuk melakukan triknya, jalankan snipet kode di bawah ini

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

di sini adalah bagaimana menggunakannya

range (Mulai, Akhir, Langkah = 1, Offset = 0);

  • inklusif - maju range(5,10) // [5, 6, 7, 8, 9, 10]
  • inklusif - terbelakang range(10,5) // [10, 9, 8, 7, 6, 5]
  • langkah mundur range(10,2,2) // [10, 8, 6, 4, 2]
  • eksklusif - maju range(5,10,0,-1) // [6, 7, 8, 9] not 5,10 themselves
  • offset - perluas range(5,10,0,1) // [4, 5, 6, 7, 8, 9, 10, 11]
  • mengimbangi - menyusut range(5,10,0,-2) // [7, 8]
  • langkah - perluas range(10,0,2,2) // [12, 10, 8, 6, 4, 2, 0, -2]

semoga bermanfaat.


Dan inilah cara kerjanya.

Pada dasarnya saya pertama-tama menghitung panjang array yang dihasilkan dan membuat nol array diisi untuk panjang itu, kemudian mengisinya dengan nilai-nilai yang dibutuhkan

  • (step || 1)=> Dan yang lain seperti ini berarti menggunakan nilai stepdan jika tidak disediakan gunakan 1sebagai gantinya
  • Kita mulai dengan menghitung panjang array hasil yang digunakan (Math.abs(end - start) + ((offset || 0) * 2)) / (step || 1) + 1)untuk membuatnya lebih sederhana (perbedaan * offset di kedua arah / langkah)
  • Setelah mendapatkan panjangnya, lalu kita buat array kosong dengan nilai yang diinisialisasi menggunakan new Array(length).fill(0); cek di sini
  • Sekarang kita memiliki array [0,0,0,..]dengan panjang yang kita inginkan. Kami memetakannya dan mengembalikan array baru dengan nilai yang kami butuhkanArray.map(function() {})
  • var direction = start < end ? 1 : 0;Tentunya jika starttidak lebih kecil dari yang endkita butuhkan untuk mundur. Maksud saya pergi dari 0 ke 5 atau sebaliknya
  • Pada setiap iterasi, startingPoint+ stepSize* indexakan memberi kita nilai yang kita butuhkan
azerafati
sumber
8
Berguna, tentu saja. Sederhana? Saya mohon untuk berbeda; terlepas dari itu Anda menjadikannya liner satu. Datang dari Python ini mengejutkan.
PascalVKooten
@ Pascalvootoot, ya tentu saja akan lebih bagus jika ada metode built-in untuk itu seperti python kurasa, tapi ini adalah yang paling sederhana yang bisa saya dapatkan. Dan itu terbukti berguna dalam proyek saya.
azerafati
Memposting potongan kode yang sangat rumit seperti itu, terutama sebagai satu-baris dan tanpa penjelasan tentang cara kerjanya? Contoh yang buruk dari yang baik jawaban SO, terlepas dari apakah atau tidak itu "bekerja".
Madbreak
1
@Madbreaks, ya Anda benar. Saya sudah naif untuk membuatnya menjadi satu liner. hanya ingin memberi semua orang solusi cepat dan mudah
azerafati
22
var range = (l,r) => new Array(r - l).fill().map((_,k) => k + l);
Klesun
sumber
@nikkwong, _itu hanya nama argumen dalam pemetaan panggilan balik. Anda tahu, dalam beberapa bahasa Anda akan menggunakan _sebagai nama untuk menunjukkan bahwa variabel tidak digunakan.
Klesun
Namun, di _sini tidak diteruskan argumen ke range. Kenapa tidak?
nikk wong
2
Sangat rapi! Meskipun, penting untuk dicatat bahwa itu tidak berfungsi pada IE atau Opera.
Rafael Xavier
4
Jawaban ini perlu penjelasan, karena cocok untuk SO.
Madbreak
@RafaelXavier akan bekerja pada IE dengan Array.fill () polyfill
mwag
18

Menggunakan fungsi Harmony spread operator dan panah:

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

Contoh:

range(10, 15);
[ 10, 11, 12, 13, 14, 15 ]
cPu1
sumber
itu jawaban terbaik!
Henry H.
1
Bukan yang tercepat sekalipun.
mjwrazor
Apa yang digarisbawahi simbol '_' dalam kasus ini?
Oleh Berehovskyi
@OlehBerehovskyi Ini berarti parameter fungsi lambda yang tidak ingin Anda gunakan. Linter yang memperingatkan tentang variabel yang tidak digunakan harus mengabaikannya.
Micah Zoltu
18

--- PEMBARUAN (Terima kasih kepada @lokhmakov untuk penyederhanaan) ---

Versi lain menggunakan generator ES6 (lihat jawaban Paolo Moretti dengan generator ES6 ):

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

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

Atau, jika hanya perlu diubah, maka:

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

--- kode ORGINAL adalah: ---

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

dan

const RANGE_ITER = (a,b) => (function*(x,y){
  while (x <= y) yield x++;
})(a,b);
Pahlawan Qu
sumber
1
Hanya const range = (x, y) => Array.from(function* () { while (x <= y) yield x++; }())
lokhmakov
@lokhmakov Ya, Anda benar. Terima kasih! Hanya menerapkan kode Anda dalam jawaban saya.
Pahlawan Qu
15

Melakukan penelitian pada beberapa Fungsi Range. Lihat perbandingan jsperf tentang berbagai cara untuk melakukan fungsi-fungsi ini. Tentu saja bukan daftar yang sempurna atau lengkap, tetapi harus membantu :)

Pemenangnya adalah...

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

Secara teknis itu bukan yang tercepat di firefox, tetapi perbedaan kecepatan gila (imho) pada chrome membuatnya untuk itu.

Pengamatan yang menarik adalah seberapa cepat chrome menggunakan fungsi array ini daripada firefox Chrome setidaknya 4 atau 5 kali lebih cepat .

Justin
sumber
Perhatikan bahwa ini dibandingkan dengan fungsi rentang yang menyertakan parameter ukuran langkah
binaryfunt
15

Javascript standar tidak memiliki fungsi bawaan untuk menghasilkan rentang. Beberapa kerangka kerja javascript menambahkan dukungan untuk fitur-fitur seperti itu, atau seperti yang orang lain tunjukkan, Anda selalu dapat menjalankannya sendiri.

Jika Anda ingin memeriksa ulang, sumber daya definitif adalah ECMA-262 Standard .

Mike Dinescu
sumber
Meskipun saya yakin jawaban yang sangat baik pada tahun 2010, ini seharusnya tidak lagi dianggap pendekatan terbaik. Anda seharusnya tidak memperluas tipe bawaan, seperti yang cenderung dilakukan oleh Prototype.j
Dana Woodman
@DanaWoodman terima kasih telah membahas ini - Saya telah memperbarui jawaban untuk mengeluarkan referensi ke Prototype.js karena itu memang cukup usang pada tahun 2018
Mike Dinescu
21
Yah ini sama sekali tidak membantu.
Pithikos
@Pithikos Saya melihat pertanyaan ini telah diedit sejak awalnya ditanyakan dan OP ingin tahu apakah ada fungsi rentang asli di JS.
Mike Dinescu
13

Anda dapat menggunakan lodash atau Undescore.js range :

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

Sebagai alternatif, jika Anda hanya perlu berbagai bilangan bulat berturut-turut, Anda dapat melakukan sesuatu seperti:

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

Dalam ES6 rangedapat diimplementasikan dengan generator :

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

Implementasi ini menghemat memori saat mengulang urutan besar, karena tidak harus mematerialisasikan semua nilai ke dalam array:

for (let i of range(1, oneZillion)) {
  console.log(i);
}
Paolo Moretti
sumber
Bagian ES6 sekarang merupakan jawaban yang benar untuk pertanyaan ini. Saya akan merekomendasikan menghapus bagian lain, yang dicakup oleh jawaban lain.
joews 8'15
generator agak aneh jika digunakan di luar loop: x = range (1, 10); // {} x; // {} // terlihat seperti peta kosong WTF!?! x.next (). value; // OK 1; x [3] // tidak terdefinisi, hanya dengan array nyata
Anona112
@ Anona112 dapat Anda gunakan Array.fromuntuk mengonversi generator ke array instance dan memeriksa output.
Paolo Moretti
10

Tantangan yang menarik adalah menulis fungsi terpendek untuk melakukan ini. Rekursi untuk menyelamatkan!

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

Cenderung lambat pada rentang yang luas, tetapi untungnya komputer kuantum sudah dekat.

Bonus tambahan adalah bahwa itu membingungkan. Karena kita semua tahu betapa pentingnya menyembunyikan kode kita dari mencongkel mata.

Untuk benar-benar dan sama sekali mengaburkan fungsi, lakukan ini:

function r(a,b){return (a<b?[a,b].concat(r(++a,--b)):a>b?[]:[a]).sort(function(a,b){return a-b})}
Rick Hitchcock
sumber
4
Pendek! = Sederhana, tetapi lebih sederhana lebih baik. Ini versi yang lebih mudah dibaca const range = (a, b) => (a>=b) ? [] : [a, ...range(a+1, b)]:, menggunakan sintaks
ES6
1
@nafg: const range = (a, b, Δ = 1) => (a > b) ? [] : [a, ...range(a + Δ, b, Δ)];. Juga mengangkat seluruh jawaban untuk komentar.
7vujy0f0hy
10

Ini mungkin bukan cara terbaik. Tetapi jika Anda mencari untuk mendapatkan kisaran angka dalam satu baris kode. Misalnya 10 - 50

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

Di mana 40 adalah (akhir - awal) dan 10 adalah awal. Ini seharusnya mengembalikan [10, 11, ..., 50]

Edison D'souza
sumber
9

Saya akan kode sesuatu seperti ini:

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]

Berperilaku mirip dengan rentang Python:

>>> range(-4,2)
[-4, -3, -2, -1, 0, 1]
Sasha Zezulinsky
sumber
8

Implementasi yang agak minimalis yang banyak mempekerjakan ES6 dapat dibuat sebagai berikut, menarik perhatian khusus pada Array.from()metode statis:

const getRange = (start, stop) => Array.from(
  new Array((stop - start) + 1),
  (_, i) => i + start
);
IsenrichO
sumber
Sebagai catatan, saya telah menciptakan inti di mana saya membuat semacam getRange()fungsi "ditingkatkan" . Secara khusus, saya bertujuan untuk menangkap kasus tepi yang mungkin tidak tertangani dalam varian telanjang-tulang di atas. Selain itu, saya menambahkan dukungan untuk rentang alfanumerik. Dengan kata lain, menyebutnya dengan dua input yang disediakan seperti 'C'dan 'K'(dalam urutan itu) mengembalikan array yang nilainya adalah serangkaian karakter berurutan dari huruf 'C' (inklusif) melalui huruf 'K' (eksklusif):getRange('C', 'K'); // => ["C", "D", "E", "F", "G", "H", "I", "J"]
IsenrichO
Anda tidak memerlukan newkata kunci
Soldeplata Saketos
8

range(start,end,step): Dengan ES6 Iterators

Anda hanya meminta batas atas dan bawah. Di sini kita membuat satu dengan langkah juga.

Anda dapat dengan mudah membuat range()fungsi generator yang dapat berfungsi sebagai iterator. Ini berarti Anda tidak perlu membuat-pre seluruh array.

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

Sekarang Anda mungkin ingin membuat sesuatu yang pra-menghasilkan array dari iterator dan mengembalikan daftar. Ini berguna untuk fungsi yang menerima array. Untuk ini bisa kita gunakanArray.from()

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

Sekarang Anda dapat membuat array statis dengan mudah,

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

Tetapi ketika sesuatu menginginkan iterator (atau memberi Anda pilihan untuk menggunakan iterator), Anda juga dapat membuatnya dengan mudah.

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

Catatan khusus

Evan Carroll
sumber
7

Meskipun ini bukan dari PHP , tetapi tiruan rangedari 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] 

sumber
+1 untuk yang tercepat. dengan array -36768 - 36768, mengambil 3ms, tempat ke-2 adalah 13 ms dan memiliki garis merah IDE.
mjwrazor
7

Sejauh menghasilkan array numerik untuk rentang tertentu, saya menggunakan ini:

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]

Jelas, itu tidak akan berfungsi untuk array alfabet.

jhaskell
sumber
Pengaturan array = []di dalam loop mungkin tidak memberikan apa yang Anda inginkan.
alex
@alex, terima kasih. Anda benar, saya juga lupa menambahkan parameter "mulai" pada setiap lintasan loop. Sudah diperbaiki sekarang.
jhaskell
Itu masih tidak akan menghasilkan output yang diinginkan, jika saya ingin rentang 5-10, itu akan memberi saya [5, 6, 7, 8, 9, 10, 11, 12, 13, 14], saya akan berharap hanya setengah dari array itu.
alex
@ alex, terima kasih lagi, saya tidak mempertimbangkan batasan panjang berdasarkan input. Lihat versi terbaru.
jhaskell
6

Menggunakan generator Harmony , didukung oleh semua browser kecuali 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;
        }
    }
});

Contohnya

mengambil

Contoh 1.

take hanya membutuhkan sebanyak yang bisa didapat

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

kembali

[100, 105, 110, 115, 120]

Contoh 2.

to tidak perlu

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

kembali

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

ambil semua

Contoh 3.

from tidak perlu

takeAll( range( {to: 5} ) )

kembali

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

Contoh 4

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

kembali

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

Contoh 5.

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

kembali

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

Janus Troelsen
sumber
Diedit dengan saran saya :)
Xotic750
+1 untuk pendekatan. Untuk titik @ alex, tidak memiliki operasi ternary (terutama tidak bersarang) dalam forklausa akan meningkatkan keterbacaan di sini.
Justin Johnson
5

... jangkauan lebih jauh, menggunakan fungsi generator.

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.

Semoga ini bermanfaat.

John Swindin
sumber
5

Rekan kerja codegolf saya membuat ini (ES6), termasuk:

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

tidak termasuk:

(s,f)=>[...Array(f-s)].map((e,i)=>i+s)
Marc Sloth Eastman
sumber
4

d3 juga memiliki fungsi rentang bawaan. Lihat https://github.com/mbostock/d3/wiki/Arrays#d3_range :

d3.range ([mulai,] hentikan [, langkah])

Menghasilkan array yang berisi perkembangan aritmatika, mirip dengan rentang bawaan Python. Metode ini sering digunakan untuk beralih pada urutan nilai numerik atau bilangan bulat, seperti indeks ke dalam array. Berbeda dengan versi Python, argumen tidak harus bilangan bulat, meskipun hasilnya lebih dapat diprediksi jika mereka disebabkan oleh presisi floating point. Jika langkah dihilangkan, standarnya adalah 1.

Contoh:

d3.range(10)
// returns [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Bob Baxley
sumber
Saya tidak pernah tahu D3 ada. Tidak akan menggunakan metode jangkauan mereka tetapi akan menggunakan paket ini.
mjwrazor
Terima kasih banyak. Saya menggunakan D3 dan sedang mencari metode JS asli, tidak tahu bahwa saya D3 sudah menawarkannya.
cezar
4

Selesaikan implementasi ES6 menggunakan tanda tangan range ([start,] stop [, step]):

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

Jika Anda ingin melangkah negatif secara otomatis, tambahkan

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

Atau lebih minimalis:

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

Jika Anda memiliki rentang besar, lihat pendekatan generator Paolo Moretti

Anona112
sumber
Ganti !stopdengan typeof stop === 'undefined', lalu ganti intdengan Math.floor, dan tambahkan cek if (start > stop && step > 0)(jika tidak, range(-3, -10)lempar pengecualian daripada melakukan sesuatu yang waras (baik membalik tanda langkah atau kembali [])). Kalau tidak, bagus!
Ahmed Fasih
4

Ada modul npm bereich untuk itu ("bereich" adalah kata Jerman untuk "range"). Itu menggunakan iterators JavaScript modern, sehingga Anda dapat menggunakannya dengan berbagai cara, seperti:

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)) {
  // ...
}

Ini juga mendukung rentang menurun (hanya dengan bertukar mindan max), dan juga mendukung langkah selain 1.

Penafian: Saya adalah pembuat modul ini, jadi tolong jawab jawaban saya dengan sebutir garam.

Golo Roden
sumber
4

Yang ini bekerja juga secara terbalik.

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 ]
Rocco Ghielmini
sumber