JavaScript có một phương thức như phạm vi phạm vi () phạm vi để tạo một phạm vi trong giới hạn được cung cấp không?


872

Trong PHP, bạn có thể làm ...

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

Đó là, có một chức năng cho phép bạn có được một loạt các số hoặc ký tự bằng cách vượt qua giới hạn trên và dưới.

Có bất cứ điều gì được tích hợp sẵn trong JavaScript cho việc này không? Nếu không, tôi sẽ thực hiện nó như thế nào?


1
Prototype.js có $Rchức năng, nhưng khác hơn là tôi không thực sự nghĩ như vậy.
Yi Jiang

Câu hỏi (có liên quan) này có một số câu trả lời xuất sắc: stackoverflow.com/questions/6299500/ cấp
btk

Array.from("ABC") //['A', 'B', 'C']Đây là điều gần nhất tôi có thể tìm thấy cho phần thứ hai của câu hỏi.
Andrew_1510

@ Andrew_1510 Bạn cũng có thể sử dụng split("")ở đó
alex

1
Khi người yêu bị ràng buộc bằng không, oneliner này:Array.apply(null, { length: 10 }).map(eval.call, Number)
csharpfolk

Câu trả lời:


1501

Số

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

Lặp lại nhân vật

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

Lặp lại

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"

Là chức năng

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

Như chức năng gõ

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()chức năng

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

Các trình duyệt non es6 cũ không có thư viện:

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

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

(Tín dụng ES6 cho nils petersohn và các nhà bình luận khác)


72
Bởi vì nếu nó hữu ích ở bất cứ đâu thì nó có thể hữu ích trong JS. (JS có thể thực hiện công cụ loại lập trình chức năng, có thể hưởng lợi từ một phạm vi (câu lệnh 0. Điều đó và hàng ngàn lý do khác có thể hữu ích trong một số trường hợp semirare)
Lodewijk

5
Bất cứ ý tưởng tại sao chỉ đơn giản là sử dụng (new Array(5)).map(function (value, index) { return index; })sẽ không làm việc? Điều này trả lại [undefined × 5]cho tôi trong Chrome DevTools.
Lewis

12
@Lewis Bởi vì một mảng được xác định có các vị trí trống sẽ không được lặp lại với map()hoặc một trong những người bạn của nó.
alex

65
Array.from (Array (5) .keys ())
nils petersohn

17
Array(5).fill()cũng có thể lập bản đồ
nils petersohn

333

Đối với các số bạn có thể sử dụng ES6 Array.from(), hoạt động trong mọi thứ hiện nay ngoại trừ IE:

Phiên bản ngắn hơn:

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

Phiên bản dài hơn:

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

trong đó tạo ra một mảng từ 0 đến 19. Điều này có thể được rút ngắn hơn nữa thành một trong những hình thức sau:

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

Giới hạn dưới và trên cũng có thể được chỉ định, ví dụ:

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

Một bài viết mô tả điều này chi tiết hơn: http://www.2ality.com/2014/05/es6-array-methods.html


50
Ví dụ đầu tiên thậm chí có thể được đơn giản hóa thành [... Array (20) .keys ()]
Delapouite

27
Hơi ngắn gọn hơn Array.from()phương pháp và nhanh hơn cả hai:Array(20).fill().map((_, i) => i)
Stu Cox

2
@Delapouite Tuyệt vời! Bạn nên làm cho nó một câu trả lời riêng biệt, và tôi sẽ bỏ phiếu cho nó! Đó cũng là câu trả lời hoàn hảo cho bản sao này .
jib

9
@Delapouite @jib Và điều này cũng vậy:Array.from({length: end - start}, (v, k) => k + start)
Aditya Singh

1
@ icc97 Có, linters có thể khiếu nại, mặc dù trong JavaScript bỏ qua một đối số chức năng được xác định là giống như vượt qua undefined, vì vậy fill()(không có đối số) không sai mỗi se. Giá trị điền không được sử dụng trong giải pháp đó, vì vậy nếu bạn muốn, bạn có thể sử dụng fill(0)để lưu một vài ký tự.
Stu Cox

122

Mẫu yêu thích mới của tôi ( ES2015 )

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

Và nếu bạn cần một hàm với stepparam:

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

5
hãy để phạm vi = (bắt đầu, dừng lại, bước = 1) => Mảng (dừng - bắt đầu) .fill (bắt đầu) .map ((x, y) => x + y * bước)
Rodiftsou

4
@rodfersou FYI: ví dụ của bạn sai. stopkhông thực sự là vị trí dừng / kết thúc mà là đếm / khoảng cách. (không xúc phạm, chỉ để mọi người biết về lỗi đánh máy)
F Lekschas 26/07/18

4
Đối với sự nhầm lẫn - do chỉnh sửa của Rodiftsou sau bình luận của F Lekschas, mã của anh ta hiện đã chính xác.
eedrah

1
Đối số mà bạn đưa vào Array(Math.ceil((stop - start) / step) + 1), cần +1đến cuối cùng, để thực sự bắt chước hành vi "bao hàm" của php.
Johan Dettmar

3
Đây là câu trả lời hàng đầu thực sự trả lời câu hỏi đầy đủ của một hàm Javascript thực hiện đầy đủ một rangephương thức. Tất cả những cái khác hiện đang ở trên này (ngoại trừ lodash _.range) đều thực hiện các trình vòng lặp cơ bản thay vì một hàm phạm vi thực tế với bắt đầu, dừng và bước
icc97

99

Đây là 2 xu của tôi:

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

1
Sử dụng tuyệt vời các chức năng bậc cao.
Farzad YZ

5
Điều này thực sự sai vì câu hỏi đang yêu cầu giá trị bắt đầu và kết thúc. Không bắt đầu & đếm / khoảng cách.
James Robey

73

Nó hoạt động cho các ký tự và số, tiến hoặc lùi với một bước tùy chọn.

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 .

Nếu tăng các kiểu bản địa là việc của bạn, thì hãy gán nó cho Array.range.


53

Chức năng phạm vi đơn giản:

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

Để kết hợp kiểu dữ liệu BitInt, có thể đưa vào một số kiểm tra, đảm bảo rằng tất cả các biến đều giống nhau 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;
}

Để loại bỏ các giá trị cao hơn được xác định bởi stopví dụ range(0,5,2)sẽ bao gồm 6, không nên.

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

3
PLUS UNO cho có thể sử dụng và đọc được. Đoạn mã tốt nhất tôi đã thấy trong một thời gian dài.
monsto 7/12/2015

1
Điều này không hoạt động khi step != 1, whileđiều kiện cần phải tính stepđến. Phiên bản cập nhật của tôi với stepgiá trị mặc định : phạm vi chức năng (bắt đầu, dừng, bước) {step = step || 1 var a = [bắt đầu], b = bắt đầu; while ((b + step) <stop) {console.log ("b:" + b + ". a:" + a + "."); b + = bước; a.push (b); } trả lại a; }
daveharris

@daveharris Tôi đã thêm một bước mặc định ở trên , (step || 1).
Ông 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']

Bạn thực sự không nên dùng phương pháp jerry-giàn lên Arraynguyên mẫu.
Connectyourcharger

Phương pháp này chỉ hoạt động với số nguyên và ký tự. Nếu các tham số là null, không xác định, NaN, boolean, mảng, đối tượng, v.v., phương thức này trả về lỗi sau : undefined method toUpperCase to etc!
Victor

`` `if (typeof from! == 'number' && typeof from! == 'string') {throw TypeError mới ('Tham số đầu tiên phải là số hoặc ký tự')} if (typeof to! == ' số '&& typeof to! ==' chuỗi ') {ném TypeError mới (' Tham số đầu tiên phải là số hoặc ký tự ')} `` `
Victor

36

OK, trong JavaScript, chúng tôi không có range()chức năng như PHP , vì vậy chúng tôi cần tạo chức năng khá dễ dàng, tôi viết vài hàm một dòng cho bạn và tách chúng cho SốBảng chữ cái như sau:

cho số :

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

và gọi nó như:

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

cho bảng chữ cái :

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

và gọi nó như:

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

2
Tôi nghĩ rằng có những lỗi khác nhau trong các chức năng này. Nên Array(end - start + 1), và Array(end.charCodeAt(0) - start.charCodeAt(0) + 1).
Earcanal

24

Chức năng tiện dụng để thực hiện thủ thuật, chạy đoạn mã dưới đây

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

đây là cách sử dụng nó

phạm vi (Bắt đầu, Kết thúc, Bước = 1, Offset = 0);

  • bao gồm - chuyển tiếp range(5,10) // [5, 6, 7, 8, 9, 10]
  • bao gồm - lạc hậu range(10,5) // [10, 9, 8, 7, 6, 5]
  • Bước giật lùi range(10,2,2) // [10, 8, 6, 4, 2]
  • độc quyền - chuyển tiếp range(5,10,0,-1) // [6, 7, 8, 9] not 5,10 themselves
  • bù đắp - mở rộng range(5,10,0,1) // [4, 5, 6, 7, 8, 9, 10, 11]
  • bù - co lại range(5,10,0,-2) // [7, 8]
  • bước - mở rộng range(10,0,2,2) // [12, 10, 8, 6, 4, 2, 0, -2]

Hi vọng bạn tìm được thứ hữu dụng.


Và đây là cách nó hoạt động.

Về cơ bản, trước tiên tôi sẽ tính toán độ dài của mảng kết quả và tạo một mảng được lấp đầy bằng 0 với độ dài đó, sau đó điền nó với các giá trị cần thiết

  • (step || 1)=> Và những người khác như thế này có nghĩa là sử dụng giá trị của stepvà nếu nó không được cung cấp sử dụng 1thay thế
  • Chúng tôi bắt đầu bằng cách tính độ dài của mảng kết quả bằng cách sử dụng (Math.abs(end - start) + ((offset || 0) * 2)) / (step || 1) + 1)để đơn giản hơn (chênh lệch * bù theo cả hai hướng / bước)
  • Sau khi nhận được độ dài, sau đó chúng tôi tạo một mảng trống với các giá trị được khởi tạo bằng cách sử dụng new Array(length).fill(0); kiểm tra tại đây
  • Bây giờ chúng ta có một mảng [0,0,0,..]theo chiều dài mà chúng ta muốn. Chúng tôi ánh xạ qua nó và trả về một mảng mới với các giá trị chúng tôi cần bằng cách sử dụngArray.map(function() {})
  • var direction = start < end ? 1 : 0;Rõ ràng nếu startkhông nhỏ hơn endchúng ta cần phải lùi lại. Ý tôi là đi từ 0 đến 5 hoặc ngược lại
  • Trên mỗi lần lặp, startingPoint+ stepSize* indexsẽ cho chúng ta giá trị chúng ta cần

8
Tiện dụng, chắc chắn nhất. Đơn giản? Tôi có ý kiến ​​khác; bất kể bạn làm cho nó một lót. Đến từ Python đây là một cú sốc.
PascalVKooten

@PascalvKooten, vâng tất nhiên sẽ rất tuyệt nếu có phương pháp tích hợp sẵn cho con trăn như tôi đoán, nhưng đây là cách đơn giản nhất tôi có thể đi qua. Và nó đã được chứng minh là tiện dụng trong các dự án của tôi.
azerafati 3/03/2016

Đăng một đoạn mã phức tạp đau đớn như thế, đặc biệt là một đoạn mã và không có lời giải thích về cách thức hoạt động của nó? Ví dụ kém về một câu trả lời SO tốt , bất kể nó có "hoạt động" hay không.
Madbreaks

1
@Madbreaks, đúng vậy. Tôi đã ngây thơ để làm cho nó một lót. chỉ muốn cung cấp cho mọi người một giải pháp nhanh chóng và dễ dàng
azerafati

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

@nikkwong, _chỉ là một tên của đối số trong cuộc gọi lại ánh xạ. Bạn biết đấy, trong một số ngôn ngữ bạn sẽ sử dụng _làm tên để chỉ ra rằng biến không được sử dụng.
Klesun

Mặc dù ở đây, _không được thông qua các đối số để range. Tại sao không?
nikk wong

2
Rât gọn gang! Mặc dù, điều quan trọng cần lưu ý là nó không hoạt động trên bất kỳ IE hoặc Opera nào.
Rafael Xavier

4
Câu trả lời này cần giải thích, vì nó phù hợp với SO.
Madbreaks

@RafaelXavier sẽ hoạt động trên IE với polyfill Array.fill ()
mwag

18

Sử dụng toán tử lây lan Harmony và các hàm mũi tên:

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

Thí dụ:

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

đó là câu trả lời tốt nhất
Henry H.

1
Không phải là nhanh nhất mặc dù.
mjwrazor

Biểu tượng gạch dưới '_' thể hiện điều gì trong trường hợp này?
Oleh Berehovskyi

@OlehBerehovskyi Nó có nghĩa là một tham số chức năng lambda mà bạn không có ý định thực sự sử dụng. Một kẻ nói dối cảnh báo về các biến không sử dụng nên bỏ qua nó.
Micah Zoltu 16/03/19

18

--- CẬP NHẬT (Cảm ơn @lokhmakov đã đơn giản hóa) ---

Một phiên bản khác sử dụng máy phát ES6 (xem câu trả lời tuyệt vời của Paolo Moretti với máy phát ES6 ):

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

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

Hoặc, nếu chúng ta chỉ cần lặp lại, thì:

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

--- Mã ORGINAL là: ---

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

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

1
Chỉ cần const range = (x, y) => Array.from(function* () { while (x <= y) yield x++; }())
lokhmakov

@lokhmakov Vâng, bạn nói đúng. cảm ơn bạn! Chỉ cần áp dụng mã của bạn trong câu trả lời của tôi.
Anh hùng Qu

15

Đã làm một số nghiên cứu về một số chức năng phạm vi khác nhau. Kiểm tra so sánh jsperf của các cách khác nhau để thực hiện các chức năng này. Chắc chắn không phải là một danh sách hoàn hảo hoặc đầy đủ, nhưng sẽ giúp :)

Người thắng cuộc là...

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

Về mặt kỹ thuật, nó không phải là nhanh nhất trên firefox, nhưng sự khác biệt tốc độ điên rồ (imho) trên chrome bù cho nó.

Một quan sát thú vị nữa là chrome có các hàm này nhanh hơn bao nhiêu so với firefox. Chrome nhanh hơn ít nhất 4 hoặc 5 lần .


Lưu ý rằng điều này được so sánh với các hàm phạm vi bao gồm tham số kích thước bước
binaryfunt

15

Javascript tiêu chuẩn không có chức năng tích hợp để tạo phạm vi. Một số khung javascript thêm hỗ trợ cho các tính năng như vậy hoặc như những người khác đã chỉ ra rằng bạn luôn có thể tự cuộn.

Nếu bạn muốn kiểm tra kỹ, tài nguyên chính xác là Tiêu chuẩn ECMA-262 .


Mặc dù tôi chắc chắn rằng một câu trả lời hoàn toàn tốt trong năm 2010, nhưng điều này không còn được coi là phương pháp tốt nhất. Bạn không nên mở rộng các loại được xây dựng, như Prototype.js có xu hướng làm 👍
Dana Woodman

@DanaWoodman cảm ơn vì đã đưa ra điều này - Tôi đã cập nhật câu trả lời để đưa ra tham chiếu đến Prototype.js vì điều đó thực sự khá lỗi thời vào năm 2018
Mike Dinescu

21
Vâng, điều này không giúp được gì cả.
Pithikos

@Pithikos Tôi thấy câu hỏi này đã được chỉnh sửa kể từ khi được hỏi ban đầu và OP muốn biết liệu có một hàm phạm vi riêng trong JS không.
Mike Dinescu

13

Bạn có thể sử dụng lodash hoặc Undescore.js range :

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

Ngoài ra, nếu bạn chỉ cần một loạt số nguyên liên tiếp, bạn có thể làm một số thứ như:

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

Trong ES6 rangecó thể được thực hiện với các trình tạo :

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

Việc triển khai này giúp tiết kiệm bộ nhớ khi lặp lại các chuỗi lớn, vì nó không phải cụ thể hóa tất cả các giá trị thành một mảng:

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

Phần ES6 hiện là câu trả lời chính xác cho câu hỏi này. Tôi sẽ khuyên bạn nên loại bỏ các phần khác, được bao phủ bởi các câu trả lời khác.
tham gia

các trình tạo có phần lạ nếu được sử dụng bên ngoài một vòng lặp: x = phạm vi (1, 10); // {} x; // {} // trông giống như một bản đồ trống WTF!?! x.next (). value; // OK 1; x [3] // không xác định, chỉ với mảng thực
Anona112

@ Anona112 bạn có thể sử dụng Array.fromđể chuyển đổi các trình tạo thành các thể hiện mảng và kiểm tra đầu ra.
Paolo Moretti

10

Một thách thức thú vị sẽ là viết hàm ngắn nhất để làm điều này. Đệ quy để giải cứu!

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

Có xu hướng chậm trên phạm vi lớn, nhưng may mắn là máy tính lượng tử chỉ ở quanh góc.

Một phần thưởng bổ sung là nó gây khó chịu. Bởi vì tất cả chúng ta đều biết tầm quan trọng của việc che giấu mã của chúng ta khỏi con mắt tò mò.

Để thực sự và hoàn toàn làm xáo trộn chức năng, hãy làm điều này:

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

4
Ngắn! = Đơn giản, nhưng đơn giản hơn là tốt hơn. Đây là phiên bản dễ đọc hơn : const range = (a, b) => (a>=b) ? [] : [a, ...range(a+1, b)], sử dụng cú pháp
ES6

1
@nafg : const range = (a, b, Δ = 1) => (a > b) ? [] : [a, ...range(a + Δ, b, Δ)];. Cũng nâng cao toàn bộ câu trả lời cho nhận xét.
7vujy0f0hy

10

Đây có thể không phải là cách tốt nhất. Nhưng nếu bạn đang tìm kiếm để có được một loạt các số trong một dòng mã. Ví dụ 10 - 50

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

Trong đó 40 là (kết thúc - bắt đầu) và 10 là bắt đầu. Điều này sẽ trả về [10, 11, ..., 50]


9

Tôi sẽ mã hóa một cái gì đó như thế này:

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]

Nó hoạt động tương tự như phạm vi Python:

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

8

Một triển khai khá tối giản sử dụng nhiều ES6 có thể được tạo ra như sau, thu hút sự chú ý đặc biệt đến Array.from()phương thức tĩnh:

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

Như một lưu ý phụ, tôi đã tạo ra một Gist trong đó tôi đã thực hiện getRange()chức năng "nâng cao" các loại. Cụ thể, tôi nhằm mục đích chụp các trường hợp cạnh có thể không được giải nén trong biến thể xương trần ở trên. Ngoài ra, tôi đã thêm hỗ trợ cho phạm vi chữ và số. Nói cách khác, gọi nó bằng hai đầu vào được cung cấp như 'C''K'(theo thứ tự đó) trả về một mảng có giá trị là tập hợp các ký tự từ chữ 'C' (bao gồm) thông qua chữ 'K' (độc quyền):getRange('C', 'K'); // => ["C", "D", "E", "F", "G", "H", "I", "J"]
IsenrichO

bạn không cần newtừ khóa
Soldeplata Saketos

8

range(start,end,step): Với ES6 Iterators

Bạn chỉ yêu cầu một giới hạn trên và dưới. Ở đây chúng tôi tạo ra một với một bước quá.

Bạn có thể dễ dàng tạo range()chức năng tạo có thể hoạt động như một trình vòng lặp. Điều này có nghĩa là bạn không phải tạo trước toàn bộ mảng.

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

Bây giờ bạn có thể muốn tạo một cái gì đó tạo trước mảng từ trình vòng lặp và trả về một danh sách. Điều này rất hữu ích cho các hàm chấp nhận một mảng. Đối với điều này, chúng ta có thể sử dụngArray.from()

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

Bây giờ bạn có thể tạo một mảng tĩnh dễ dàng,

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

Nhưng khi một cái gì đó mong muốn một trình vòng lặp (hoặc cung cấp cho bạn tùy chọn để sử dụng một trình vòng lặp), bạn cũng có thể dễ dàng tạo một trình vòng lặp.

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

Ghi chú đặc biệt


7

Mặc dù đây không phải là từ PHP , mà là bắt chước rangetừ 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] 

+1 cho nhanh nhất. với một mảng -36768 - 36768, mất 3ms, vị trí thứ 2 là 13 ms và có các đường màu đỏ IDE.
mjwrazor

7

Theo như việc tạo ra một mảng số cho một phạm vi nhất định, tôi sử dụng điều này:

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]

Rõ ràng, nó sẽ không hoạt động cho các mảng chữ cái.


Thiết lập array = []bên trong vòng lặp có thể không cung cấp cho bạn những gì bạn muốn.
alex

@alex, cảm ơn bạn. Bạn nói đúng, tôi cũng quên tăng tham số "bắt đầu" trên mỗi lần vượt qua của vòng lặp. Bây giờ nó đã được sửa.
jhaskell

Nó vẫn không tạo ra đầu ra mong muốn, nếu tôi muốn phạm vi 5-10, nó sẽ cung cấp cho tôi [5, 6, 7, 8, 9, 10, 11, 12, 13, 14], tôi chỉ mong đợi nửa đầu của mảng đó.
alex

@alex, cảm ơn bạn một lần nữa, tôi đã không xem xét một hạn chế độ dài dựa trên đầu vào. Xem phiên bản cập nhật.
jhaskell

6

Sử dụng trình tạo Harmony , được hỗ trợ bởi tất cả các trình duyệt ngoại trừ 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;
        }
    }
});

Ví dụ

lấy

Ví dụ 1.

take chỉ mất nhiều nhất có thể

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

trả lại

[100, 105, 110, 115, 120]

Ví dụ 2.

to không cần thiết

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

trả lại

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

lấy tất cả

Ví dụ 3.

from không cần thiết

takeAll( range( {to: 5} ) )

trả lại

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

Ví dụ 4.

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

trả lại

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

Ví dụ 5.

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

trả lại

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


Đã chỉnh sửa với các đề xuất của tôi :)
Xotic750

+1 cho cách tiếp cận. Theo quan điểm của @ alex, việc không có các hoạt động ternary (đặc biệt là không lồng nhau) trong formệnh đề sẽ cải thiện khả năng đọc ở đây.
Justin Johnson

5

... nhiều phạm vi hơn, sử dụng chức năng tạo.

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.

Hy vọng điều này là hữu ích.


5

Đồng nghiệp mã hóa của tôi đã đưa ra điều này (ES6), bao gồm:

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

không bao gồm:

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


4

d3 cũng có chức năng phạm vi tích hợp. Xem https://github.com/mbostock/d3/wiki/Arrays#d3_range :

d3.range ([bắt đầu,] dừng [, bước])

Tạo một mảng chứa một tiến trình số học, tương tự như phạm vi tích hợp Python. Phương pháp này thường được sử dụng để lặp qua một chuỗi các giá trị số hoặc số nguyên, chẳng hạn như các chỉ mục thành một mảng. Không giống như phiên bản Python, các đối số không bắt buộc phải là số nguyên, mặc dù kết quả có thể dự đoán được nhiều hơn nếu chúng là do độ chính xác của dấu phẩy động. Nếu bước bị bỏ qua, nó mặc định là 1.

Thí dụ:

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

Tôi chưa bao giờ biết D3 tồn tại. Không sử dụng phương pháp phạm vi của họ nhưng sẽ sử dụng gói này.
mjwrazor

Cảm ơn bạn rất nhiều. Tôi sử dụng D3 và đang tìm kiếm một phương thức JS gốc, không biết rằng tôi D3 đã cung cấp nó.
cezar

4

Hoàn thành triển khai ES6 bằng chữ ký phạm vi ([bắt đầu,] dừng [, bước]):

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

Nếu bạn muốn bước âm tự động, hãy thêm

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

Hoặc tối giản hơn:

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

Nếu bạn có phạm vi lớn, hãy nhìn vào cách tiếp cận máy phát điện của Paolo Moretti


Thay thế !stopbằng typeof stop === 'undefined', sau đó thay thế intbằng Math.floorvà thêm một kiểm tra if (start > stop && step > 0)(nếu không, range(-3, -10)sẽ ném một ngoại lệ thay vì thực hiện một cái gì đó lành mạnh (hoặc lật dấu hiệu của bước hoặc quay lại [])). Nếu không, tốt!
Ahmed Fasih

4

Có một mô-đun npm bereich cho điều đó ("bereich" là từ tiếng Đức có nghĩa là "phạm vi"). Nó sử dụng các trình lặp của JavaScript hiện đại, vì vậy bạn có thể sử dụng nó theo nhiều cách khác nhau, chẳng hạn như:

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

Nó cũng hỗ trợ các phạm vi giảm dần (bằng cách trao đổi đơn giản minmax), và nó cũng hỗ trợ các bước khác ngoài 1.

Tuyên bố miễn trừ trách nhiệm: Tôi là tác giả của mô-đun này, vì vậy hãy lấy câu trả lời của tôi bằng một hạt muối.


4

Điều này cũng hoạt động ngược lại.

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 ]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.