获取输入值范围内的排序列表中的两个数字

问题描述 投票:2回答:2

我想编写一个函数,给出一个排序的数字列表和一个随机数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长度将始终受限,并且这不会在热路径中执行),是否有更优雅的方式来编写此函数?

优雅我的意思是使用较少的代码行和/或更具功能性的东西。如果它可以处理上面的“奖励”测试,那也会很棒。

我觉得这可以用一个班轮来完成吗?

带有茉莉花测试的Here is a CodePen片段。

编辑:Woops,只是看到奖金测试有错误的输入值,使其完全不合逻辑。它应该是expect(getRange([0.2, 0.3, 0.3, 0.8] , 0.3)).toEqual([0.3, 0.3]);。以上修正过。

javascript
2个回答
3
投票

你可以使用递归:

const getRange = ([a, b, ...xs], value) => 
  xs.length === 0 || value < b
    ? [a, b]
    : getRange([b, ...xs], value);

它通过与第二个元素进行比较来工作,如果它太小则调用剩余的元素。

我专注于传递测试(让我们称之为“测试驱动”;)),但是您可能想要覆盖一些明显的边缘情况(例如,输入短于2个元素)


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]
.as-console-wrapper { max-height: 100% !important; top: 0; }
© www.soinside.com 2019 - 2024. All rights reserved.