大家好我正在尝试在javascript中创建一个函数,从范围(开始,结束)返回一个数组,并且我应该创建一个可选参数,默认为1时未定义。当我提供所有参数时,我可以使函数工作,但当我只传递两个参数时返回一个空数组。这是一个问题:
编写一个范围函数,它接受两个参数,start和end,并返回一个包含从start到(和包括)end的所有数字的数组。
接下来,编写一个sum函数,它接受一个数字数组并返回这些数字的总和。运行上一个程序,看它是否确实返回55。
作为奖励分配,修改范围函数以采用可选的第三个参数,该参数指示用于构建阵列的“步长”值。如果没有给出步骤,则数组元素以1的增量上升,对应于旧行为。函数调用范围(1,10,2)应返回[1,3,5,7,9]。确保它也适用于负步长值,以便范围(5,2,-1)产生[5,4,3,2]。
这是我的代码
function range(start, end, increment){
var array = [];
var current = start;
var counter;
if (increment == undefined){
counter = 1;
}
else {
counter = increment;
}
if (increment > 0){
while(current <= end){
array.push(current);
current += counter;
}
}
else if (increment < 0){
while(current >= end){
array.push(current);
current += counter;
}
}
return array;
}
有人可以解释为什么它会破裂吗?我知道一些c#和我过去能够在出现问题时跳入Visual Studio中的调试器,这与javascript不同
答案 0 :(得分:5)
您可以稍微简化代码并使用increment
变量进行递增。但在此之前,我建议测试该值是否为假(0
,null
,undefined
等),然后将1
分配给它。
未实施:请检查start
和end
是否合适。
function range(start, end, increment) {
var array = [];
var current = start;
increment = increment || 1;
if (increment > 0) {
while (current <= end) {
array.push(current);
current += increment;
}
} else {
while (current >= end) {
array.push(current);
current += increment;
}
}
return array;
}
console.log(range(1, 3, 0));
console.log(range(2, 5));
console.log(range(1, 9, 1));
console.log(range(5, 2, -1));
答案 1 :(得分:4)
一个非常简单的单向(升序),包含范围 - 每次从x
增加到y
增加1
。
// range :: (Int, Int) -> [Int]
const range = (x,y) =>
x > y ? [] : [x, ...range(x + 1, y)];
console.log(range(1,4)); // [1,2,3,4]
console.log(range(3,3)); // [3]
console.log(range(6,3)); // []
支持双向(升序或降序)范围的轻微调整 - 仍然按1
递增或递减
// range :: (Int, Int) -> [Int]
const range = (x,y) => {
if (x > y)
return range(y,x).reverse();
else
return x === y ? [y] : [x, ...range(x + 1, y)];
}
console.log(range(1,4)); // [1,2,3,4]
console.log(range(3,3)); // [3]
console.log(range(6,3)); // [6,5,4,3]
使用高阶函数进行更多控制范围的另一个改编 - 这有效地为你提供了一些你正在寻找的步进/递增行为 - 这更强大,因为它允许你使用函数,{{1选择下一个值。
t
此功能与const gte = x => y => y >= x;
const lte = x => y => y <= x;
const add = x => y => y + x;
const sub = x => y => y - x;
// range :: (Int, (Int -> Bool), (Int -> Int)) -> [Int]
const range = (x, p, t) => {
if (p(x))
return [x, ...range(t(x), p, t)];
else
return [];
};
console.log(range(2, lte(8), add(2))); // [2,4,6,8]
console.log(range(9, gte(0), sub(3))); // [9,6,3,0]
console.log(range(9, gte(0), sub(5))); // [9, 4]
// very power. wow.
const double = x => x + x;
console.log(range(2, lte(50), double)); // [2,4,8,16,32]
和for
具有相同的风险 - 您可以确保不要将其置于无限循环中。
功能过载
警告:未来的神秘,不切实际的功能。以下信息仅供您学术享受。
while
函数也恰好是我最喜欢的range
组合子演示之一。我将在这里向您展示两个例子。
天真Y
range
和高阶const U = f => f (f);
const Y = U (h => f => f (x => h (h) (f) (x)));
const range = Y (f => acc => x => y =>
x > y ? acc : f ([...acc, x]) (x + 1) (y)
) ([]);
console.log(range (3) (6)); // [3,4,5,6]
console.log(range (6) (6)); // [6]
console.log(range (9) (6)); // []
range
这是多么美丽的东西。
答案 2 :(得分:3)
首先检查increment
是否未定义并相应地设置counter
,但稍后再次检查if (increment > 0){
。虽然undefined
没有任何案例匹配,但没有任何事情发生。
将支票更改为:
if (counter > 0){
// ...
}
else if (counter < 0){
// ...
}
答案 3 :(得分:0)
给出的答案很棒。我只是想让你了解一个更实用的方法如何解决这个任务:
// auxiliary functions:
const append = (x, xs) => xs.concat([x]);
const prepend = (x, xs) => [x].concat(xs);
// main function
const range = (x, y, step, acc = [], op = append) =>
step && step < 0
? range(y, x, -step, acc, prepend)
: step && x <= y
? range(x + step, y, step, op(x, acc), op) // tail call
: acc;
console.log(range(1,5,1)); // [1,2,3,4,5]
console.log(range(1,5,2)); // [1,3,5]
console.log(range(1,5,6)); // [1]
console.log(range(5,1,1)); // []
console.log(range(1,5,0)); // []
console.log(range(5,1,-1)); // [5,4,3,2,1]
console.log(range(5,1,-2)); // [5,3,1]
console.log(range(5,1,-6)); // [1]
console.log(range(1,5,-1)); // []
算法:
acc = []
和op = append
默认参数值(如果在函数调用期间省略,则采用)step && step < 0
为零,则step
短路,否则检查步骤是否为负range(y, x, -step, acc, prepend)
为否定时会调用step
并转换range
的参数化,以便step
可以为正(请注意-step
是相当于-(-1)
,评估为1
)range(x + step, y, step, op(x, acc), op)
递归情况,即函数调用自身(注意op
可以是append
或prepend
,具体取决于step
的初始符号,x
增加step
并附加/添加到acc
)acc
基本情况,用于停止递归并返回累积数组答案 4 :(得分:0)
处理浮点数和负数的非常紧凑的范围函数:
const range = (lower,upper,step)=>{
return Array.from(new Array(Math.floor(upper/step-lower/step)+1),(_,i)=>lower/step+i).map(x=>x*step)
}
例如,您可以像这样使用它:
range(10,30,3) // [10, 13, 16, 19, 22, 25, 28]
range(0,0.5,0.01) // [0, 0.01, 0.02, ... , 0.48, 0.49, 0.5]
range(1,10,2) // [1, 3, 5, 7, 9]
range(-5,10,0.5) // [-5, -4.5, -4, ... , 1, 1.5, 2]
range(5,2,-0.5) // [5, 4.5, 4, 3.5, 3, 2.5, 2]
这里是一个更容易理解的版本:
const range = (lower, upper, step) => {
end = upper / step // Upper bound
start = lower / step // Lower bound
n = Math.floor(end - start) + 1 // Size that includes upper bound as well
zeros_arr = Array(n).fill(0) // Init array with n zeros
unscaled_arr = zeros_arr.map((_, i) => (start + i)) // Setting each zero to the upper bound + the index
range_arr = unscaled_arr.map(x => (x * step)) // Scaling every numbers with the step
return range_arr
}
答案 5 :(得分:0)
我在 eloquent javascript 课程中解决了这个问题。根据问题陈述,我为增量选择 default parameters 并使用 while 循环来包含第二个参数。
function range(start, stop, increment=1)
{
let range_arr = [];
if(start < stop)
{
while( start <= stop)
{
range_arr.push(start);
start += increment;
}
}
else{
while( start >= stop)
{
range_arr.push(start);
start += increment;
}
}
return range_arr;
}