JavaScript是否有像“range()”这样的方法来根据提供的边界生成一个数组?
在PHP中,你可以做…
range(1, 3); // Array(1, 2, 3) range("A", "C"); // Array("A", "B", "C")
也就是说,有一个函数可以让你通过传递上下界来得到一个数字或字符的范围。
JavaScript本身是否有内置的JavaScript? 如果不是,我将如何执行它?
lodash.js _.range()
函数
_.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]
或者没有图书馆:
Array.apply(null, Array(5)).map(function (_, i) {return i;}); => [0, 1, 2, 3, 4]
ES6版本和字符迭代
[...Array(5).keys()]; => [0, 1, 2, 3, 4] String.fromCharCode(..._.range('A'.charCodeAt(0), 'D'.charCodeAt(0) + 1)); => "ABCD"
console.log([...Array(5).keys()]);
对于数字,你可以使用ES6的Array.from()
, 这一天工作在一切,除了IE浏览器:
Array.from(new Array(20), (x,i) => i)
它创build一个从0到19的数组。 这可以进一步缩短为这些forms之一:
Array.from(Array(20).keys()) // or [...Array(20).keys()]
下限和上限也可以被指定,例如:
Array.from(new Array(20), (x,i) => i + *lowerBound*)
一篇文章更详细地描述这个: http : //www.2ality.com/2014/05/es6-array-methods.html
这是我的2美分:
function range(start, count) { return Array.apply(0, Array(count)) .map(function (element, index) { return index + start; }); }
它适用于字符和数字,向前或向后可选步骤。
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 。
如果增加本地types是你的事情,然后将其分配给Array.range
。
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; } console.log(range("A", "Z", 1)); console.log(range("Z", "A", 1)); console.log(range("A", "Z", 3)); console.log(range(0, 25, 1)); console.log(range(0, 25, 5)); console.log(range(20, 5, 5));
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']
简单的范围function:
function range(start, stop, step){ var a=[start], b=start; while(b<stop){b+=step;a.push(b)} return a; };
var range = (l,r) => new Array(r - l).fill().map((_,k) => k + l);
方便的function做的伎俩,运行下面的代码片段
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));
标准的Javascript没有内置函数来生成范围。 几个JavaScript框架添加了对这些function的支持,包括Prototype.js 。
如果您想仔细检查, 权威资源是ECMA-262标准 。
我最喜欢的forms( ES2015 )
Array(10).fill(1).map((x, y) => x + y)
使用和谐扩散运算符和箭头函数:
var range = (start, end) => [...Array(end - start + 1)].map((_, i) => start + i);
例:
range(10, 15); [ 10, 11, 12, 13, 14, 15 ]
好的,在JavaScript中,我们没有像PHP这样的range()
函数,所以我们需要创build一个非常简单的函数,我为您编写了一些单行函数,并将它们分开为Numbers和Alphabets :
数字 :
function numberRange (start, end) { return new Array(end - start).fill().map((d, i) => i + start); }
并称之为:
numberRange(5, 10); //[5, 6, 7, 8, 9]
对于字母表 :
function alphabetRange (start, end) { return new Array(end.charCodeAt(0) - start.charCodeAt(0)).fill().map((d, i) => String.fromCharCode(i + start.charCodeAt(0))); }
并称之为:
alphabetRange('c', 'h'); //["c", "d", "e", "f", "g"]
对一些范围函数做了一些研究。 检查jsperf比较不同的方法来完成这些function。 当然不是一个完美或详尽的清单,但应该帮助:)
赢家是…
function range(lowEnd,highEnd){ var arr = [], c = highEnd - lowEnd + 1; while ( c-- ) { arr[c] = highEnd-- } return arr; } range(0,31);
从技术上来说,它不是Firefox上最快的,但铬上疯狂的速度差(IMHO)弥补了它。
另外一个有趣的现象是,这些数组函数比firefox要快得多。 Chrome至less要快4到5倍 。
一个有趣的挑战将是写最短的function来做到这一点。 recursion救援!
function r(a,b){return a>b?[]:[a].concat(r(++a,b))}
量子计算机在即将到来的时候,往往会在大范围内变慢。
额外的好处是它是混淆的。 因为我们都知道隐藏我们的代码是非常重要的。
要真正完全混淆函数,请执行以下操作:
function r(a,b){return (a<b?[a,b].concat(r(++a,--b)):a>b?[]:[a]).sort(function(a,b){return ab})}
我会编写这样的代码:
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]
它的行为与Python范围类似:
>>> range(-4,2) [-4, -3, -2, -1, 0, 1]
大量采用ES6的简单实现可以如下创build,特别关注Array.from()
静态方法:
const getRange = (start, stop) => Array.from( new Array((stop - start) + 1), (_, i) => i + start );
虽然这不是来自PHP ,但是模仿Python的range
。
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]
你可以使用lodash或Undescore.js range
:
var range = require('lodash/range') range(10) // -> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
另外,如果你只需要连续的整数范围,你可以做如下的事情:
Array.apply(undefined, { length: 10 }).map(Number.call, Number) // -> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
在ES6 range
可以用发生器实现:
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; } }
这个实现在迭代大型序列时节省了内存,因为它不必将所有值实现成一个数组:
for (let i of range(1, oneZillion)) { console.log(i); }
使用Harmony生成器 , 除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; } } });
例子
采取
例1
只需要尽可能多的花费
take(10, range( {from: 100, step: 5, to: 120} ) )
回报
[100, 105, 110, 115, 120]
例2。
to
不必要的
take(10, range( {from: 100, step: 5} ) )
回报
[100, 105, 110, 115, 120, 125, 130, 135, 140, 145]
takeAll
例3。
from
不必要的
takeAll( range( {to: 5} ) )
回报
[0, 1, 2, 3, 4, 5]
例4。
takeAll( range( {to: 500, step: 100} ) )
回报
[0, 100, 200, 300, 400, 500]
例5
takeAll( range( {from: 'z', to: 'a'} ) )
回报
["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"]
另一个使用ES6生成器的版本(请参阅Paolo Moretti用ES6生成器回答 ):
const RANGE = (a,b) => Array.from((function*(x,y){ while (x <= y) yield x++; })(a,b)); console.log(RANGE(3,7)); // [ 3, 4, 5, 6, 7 ]
或者,如果我们只需要迭代,那么:
const RANGE_ITER = (a,b) => (function*(x,y){ while (x++< y) yield x; })(a,b); for (let n of RANGE_ITER(3,7)){ console.log(n); }
你可以使用lodash
函数_.range(10)
https://lodash.com/docs#range
至于生成给定范围的数组数组,我使用这个:
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]
显然,它不适用于字母数组。
D3也有一个内置的范围function。 请参阅https://github.com/mbostock/d3/wiki/Arrays#d3_range :
d3.range([start,] stop [,step])
生成一个包含算术级数的数组,类似于Python内置的范围。 此方法通常用于迭代数值或整数值的序列,例如索引到数组中。 与Python版本不同的是,参数并不要求是整数,但如果由于浮点精度,结果更具可预测性。 如果省略步骤,则默认为1。
例:
d3.range(10) // returns [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
我很惊讶地看到这个线程,看到没有像我的解决scheme(也许我错过了一个答案),所以在这里。 我在ES6语法中使用一个简单的范围函数:
// [begin, end[ const range = (b, e) => Array.apply(null, Array(e - b)).map((_, i) => {return i+b;});
但是它只在向前计数(即begin <end)时才起作用,所以我们可以在需要时稍微修改它,如下所示:
const range = (b, e) => Array.apply(null, Array(Math.abs(e - b))).map((_, i) => {return b < e ? i+b : bi;});
这里有一个很好的简单的方法来做ES6中只有数字(不知道它的速度比较):
Array.prototype.map.call(' '.repeat(1 + upper - lower), (v, i) => i + lower)
对于单个字符的范围,您可以稍微修改它:
Array.prototype.map.call(' '.repeat(1 + upper.codePointAt() - lower.codePointAt()), (v, i) => String.fromCodePoint(i + lower.codePointAt()));
完整的ES6实现使用范围([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) }
如果你想自动反向步进,添加
if(stop<start)step=-Math.abs(step)
或者更简约:
range=(b, e, step=1)=>{ if(!e){e=b;b=0} return Array.from(new Array(int((eb)/step)), (_,i) => b<e? b+i*step : bi*step) }
如果你有很大的范围看Paolo Moretti的发电机方法
我发现一个相当于PHP中的JS范围函数,在这里工作得非常好。 工作向前和向后,并与整数,花车和字母!
function range(low, high, step) { // discuss at: http://phpjs.org/functions/range/ // original by: Waldo Malqui Silva // example 1: range ( 0, 12 ); // returns 1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] // example 2: range( 0, 100, 10 ); // returns 2: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100] // example 3: range( 'a', 'i' ); // returns 3: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'] // example 4: range( 'c', 'a' ); // returns 4: ['c', 'b', 'a'] var matrix = []; var inival, endval, plus; var walker = step || 1; var chars = false; if (!isNaN(low) && !isNaN(high)) { inival = low; endval = high; } else if (isNaN(low) && isNaN(high)) { chars = true; inival = low.charCodeAt(0); endval = high.charCodeAt(0); } else { inival = (isNaN(low) ? 0 : low); endval = (isNaN(high) ? 0 : high); } plus = ((inival > endval) ? false : true); if (plus) { while (inival <= endval) { matrix.push(((chars) ? String.fromCharCode(inival) : inival)); inival += walker; } } else { while (inival >= endval) { matrix.push(((chars) ? String.fromCharCode(inival) : inival)); inival -= walker; } } return matrix; }
这里是缩小版本:
function range(h,c,b){var i=[];var d,f,e;var a=b||1;var g=false;if(!isNaN(h)&&!isNaN(c)){d=h;f=c}else{if(isNaN(h)&&isNaN(c)){g=true;d=h.charCodeAt(0);f=c.charCodeAt(0)}else{d=(isNaN(h)?0:h);f=(isNaN(c)?0:c)}}e=((d>f)?false:true);if(e){while(d<=f){i.push(((g)?String.fromCharCode(d):d));d+=a}}else{while(d>=f){i.push(((g)?String.fromCharCode(d):d));d-=a}}return i};
对于具有良好的向后兼容性的ruby般的方法:
range([begin], end = 0)
begin
和end
是数字
var range = function(begin, end) { if (typeof end === "undefined") { end = begin; begin = 0; } var result = [], modifier = end > begin ? 1 : -1; for ( var i = 0; i <= Math.abs(end - begin); i++ ) { result.push(begin + i * modifier); } return result; }
例子:
range(3); //=> [0, 1, 2, 3] range(-2); //=> [0, -1, -2] range(1, 2) //=> [1, 2] range(1, -2); //=> [1, 0, -1, -2]
这是我的解决scheme,模仿Python。 在底部,你可以find一些如何使用它的例子。 它与数字一起工作,就像Python的range
:
var assert = require('assert'); // if you use Node, otherwise remove the asserts var L = {}; // L, ie 'list' // range(start, end, step) L.range = function (a, b, c) { assert(arguments.length >= 1 && arguments.length <= 3); if (arguments.length === 3) { assert(c != 0); } var li = [], i, start, end, step, up = true; // Increasing or decreasing order? Default: increasing. if (arguments.length === 1) { start = 0; end = a; step = 1; } if (arguments.length === 2) { start = a; end = b; step = 1; } if (arguments.length === 3) { start = a; end = b; step = c; if (c < 0) { up = false; } } if (up) { for (i = start; i < end; i += step) { li.push(i); } } else { for (i = start; i > end; i += step) { li.push(i); } } return li; }
例子:
// range L.range(0) -> [] L.range(1) -> [0] L.range(2) -> [0, 1] L.range(5) -> [0, 1, 2, 3, 4] L.range(1, 5) -> [1, 2, 3, 4] L.range(6, 4) -> [] L.range(-2, 2) -> [-2, -1, 0, 1] L.range(1, 5, 1) -> [1, 2, 3, 4] L.range(0, 10, 2) -> [0, 2, 4, 6, 8] L.range(10, 2, -1) -> [10, 9, 8, 7, 6, 5, 4, 3] L.range(10, 2, -2) -> [10, 8, 6, 4]
编码到2010年规格(雅,2016年与ES6发电机)。 这里是我的看法,可以select模拟Python的range()
函数。
Array.range = function(start, end, step){ if (start == undefined) { return [] } // "undefined" check if ( (step === 0) ) { return []; // vs. throw TypeError("Invalid 'step' input") } // "step" == 0 check if (typeof start == 'number') { // number check if (typeof end == 'undefined') { // single argument input end = start; start = 0; step = 1; } if ((!step) || (typeof step != 'number')) { step = end < start ? -1 : 1; } var length = Math.max(Math.ceil((end - start) / step), 0); var out = Array(length); for (var idx = 0; idx < length; idx++, start += step) { out[idx] = start; } // Uncomment to check "end" in range() output, non pythonic if ( (out[out.length-1] + step) == end ) { // "end" check out.push(end) } } else { // Historical: '&' is the 27th letter: http://nowiknow.com/and-the-27th-letter-of-the-alphabet/ // Axiom: 'a' < 'z' and 'z' < 'A' // note: 'a' > 'A' == true ("small a > big A", try explaining it to a kid! ) var st = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&'; // axiom ordering if (typeof end == 'undefined') { // single argument input end = start; start = 'a'; } var first = st.indexOf(start); var last = st.indexOf(end); if ((!step) || (typeof step != 'number')) { step = last < first ? -1 : 1; } if ((first == -1) || (last == -1 )) { // check 'first' & 'last' return [] } var length = Math.max(Math.ceil((last - first) / step), 0); var out = Array(length); for (var idx = 0; idx < length; idx++, first += step) { out[idx] = st[first]; } // Uncomment to check "end" in range() output, non pythonic if ( (st.indexOf(out[out.length-1]) + step ) == last ) { // "end" check out.push(end) } } return out; }
例:
Array.range(5); // [0,1,2,3,4,5] Array.range(4,-4,-2); // [4, 2, 0, -2, -4] Array.range('a','d'); // ["a", "b", "c", "d"] Array.range('B','y'); // ["B", "A", "z", "y"], different from chr() ordering Array.range('f'); // ["a", "b", "c", "d", "e", "f"] Array.range(-5); // [], similar to python Array.range(-5,0) // [-5,-4-,-3-,-2,-1,0]