我想编写一个函数,给出一个排序的数字列表和一个随机数X
,将返回一个新的数组[Y, Z]
,使Y <= X < Z
。该函数还应处理输入值超出数组中所有随机数范围的边缘情况。
这就是我的想法:
const getRange = (ranges, value) => {
let rangeTopIndex = ranges.findIndex(range => value < range);
// The value must be larger than the max value in range,
// use the last range.
if (rangeTopIndex == -1) {
rangeTopIndex = ranges.length - 1
}
// The value is smaller than the first value in range,
// use the second value in range as "top" in range.
if (rangeTopIndex == 0) {
rangeTopIndex = 1;
}
// Bottom index is always the index before top.
let rangeBottomIndex = rangeTopIndex - 1;
return [ranges[rangeBottomIndex], ranges[rangeTopIndex]]
};
这些是它应该处理的测试:
describe('getRange', function() {
it('should get the correct range', () => {
// In between two values
expect(getRange([0, 0.2, 0.7, 1] , 0.5)).toEqual([0.2, 0.7]);
expect(getRange([0, 0.2, 0.7, 1] , 0.1)).toEqual([0, 0.2]);
expect(getRange([0, 0.2, 0.7, 1] , 0.2)).toEqual([0.2, 0.7]);
// Edge cases
expect(getRange([0, 0.2, 0.7, 1] , 0)).toEqual([0, 0.2]);
expect(getRange([0, 0.2, 0.7, 1] , 1)).toEqual([0.7, 1]);
// Outside boundary of range
expect(getRange([0, 0.2, 0.7, 0.8] , 0.9)).toEqual([0.7, 0.8]);
expect(getRange([0.2, 0.3, 0.7, 0.8] , 0.1)).toEqual([0.2, 0.3]);
// Bonus if getRange can handle this (not necessary for my use case):
// expect(getRange([0.2, 0.3, 0.3, 0.8] , 0.3)).toEqual([0.3, 0.3]);
});
});
鉴于性能确实不是问题(ranges
长度总是有限的,并且这不会在热门路径中执行),是否有更优雅的方式来编写此功能吗
优雅我的意思是使用较少的代码行和/或更具功能性的东西。如果它可以处理&#34;奖金&#34;在上面测试,那也很棒。
我觉得这可以用一个班轮来完成吗?
带有茉莉花测试的Here is a CodePen代码段。
编辑:Woops,只是看到奖金测试输入值错误,使其完全不合逻辑。它应该是expect(getRange([0.2, 0.3, 0.3, 0.8] , 0.3)).toEqual([0.3, 0.3]);
。以上修正了。
答案 0 :(得分:3)
你可以使用递归:
const getRange = ([a, b, ...xs], value) =>
xs.length === 0 || value < b
? [a, b]
: getRange([b, ...xs], value);
它通过与第二个元素进行比较而起作用,并且如果它太小则调用剩余的元素。
我专注于传递测试(让我们称之为&#34;测试驱动&#34 ;;)),但是您可能想要覆盖一些明显的边缘情况(输入短于2个元素,例如)
答案 1 :(得分:1)
略有不同的方法,但有
的边缘情况getRange([0, 0.2, 0.7, 1], 0.2)); // [0.2, 0.7]
返回
[0, 0.2]
从两个值小于给定结果的delta的角度来看。
const
getRange = (ranges, value) =>
ranges.reduce((r, v) =>
r.length < 2
? r.concat(v)
: Math.abs(value - r[0]) >= Math.abs(value - v)
? [r[r.length - 1], v]
: r
, []);
// In between two values
console.log(getRange([0, 0.2, 0.7, 1], 0.5)); // [0.2, 0.7]
console.log(getRange([0, 0.2, 0.7, 1], 0.1)); // [0, 0.2]
console.log(getRange([0, 0.2, 0.7, 1], 0.2)); // [0.2, 0.7]
// Edge cases
console.log(getRange([0, 0.2, 0.7, 1], 0)); // [0, 0.2]
console.log(getRange([0, 0.2, 0.7, 1], 1)); // [0.7, 1]
// Outside boundary of range
console.log(getRange([0, 0.2, 0.7, 0.8], 0.9)); // [0.7, 0.8]
console.log(getRange([0.2, 0.3, 0.7, 0.8], 0.1)); // [0.2, 0.3]
// extra
console.log(getRange([0.2, 0.3, 0.3, 0.8], 0.3)); // [0.3, 0.3]
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;