如何在带有范围的集合之间快速分配值

时间:2016-01-20 12:44:25

标签: javascript algorithm collections lodash

使用lodash和javascript。我有两个集合,我试图将其中一个集合的值分配到另一个集合中的相关范围。我最好的尝试如下所示,如何解决这种情况,但它很快就会遇到我要学习的东西被称为" quadratic complexity"对于时间问题。对于我的函数,一旦我开始获得大于大约20个值的数组,这个函数需要花费相当多的时间。

我怎样才能更快地完成这项工作?关于如何以线性方式做到这一点的任何想法?

var colA = [
    {point: 3, value: 5},
    {point: 10, value: 8},
    {point: 6, value: 18},
    {point: 12, value: 13},
    {point: 11, value: 2},
    {point: 19, value: 4},
    {point: 7, value: 2},
    {point: 8, value: 12},
];


var colB = [
    {min: 1, max: 5, value: 0},
    {min: 5, max: 10, value: 0},
    {min: 10, max: 15, value: 0},
    {min: 15, max: 20, value: 0}
];

_.forEach(colA,function(source){
    var resume = true; 
    _.forEach(colB,function(dest){

        if(resume === true && source.point >= dest.min && source.point < dest.max){
            dest.value += source.value;
            resume = false;
        }
    });
}); 

====输出====

var colB = [
    {min: 1, max: 5, value: 5},
    {min: 5, max: 10, value: 32},
    {min: 10, max: 15, value: 23},
    {min: 15, max: 20, value: 4}
];

注意:此功能已从目前的形式大大简化。这代表了我试图做的基本理论。

3 个答案:

答案 0 :(得分:1)

排序数组和非重叠范围的解决方案,显然不是lodash。

只是迭代了数组colA。 数组colB与正确范围的索引一起使用。在对此数组进行排序时,下一个合适的范围是在实际元素处或在以下元素处。如果索引位于数组的正确位置或末尾,则while循环结束。以下检查查看元素是否存在以及值是否大于或等于最小范围。

var colA = [{ point: 3, value: 5 }, { point: 10, value: 8 }, { point: 6, value: 18 }, { point: 12, value: 13 }, { point: 11, value: 2 }, { point: 19, value: 4 }, { point: 7, value: 2 }, { point: 8, value: 12 }, ],
    colB = [{ min: 1, max: 5, value: 0 }, { min: 5, max: 10, value: 0 }, { min: 10, max: 15, value: 0 }, { min: 15, max: 20, value: 0 }];

colA.sort(function (k, l) { return k.point - l.point; });
colB.sort(function (k, l) { return k.min - l.min || k.max - l.max; });

colA.reduce(function (i, aa) {
    while (i < colB.length && aa.point > colB[i].max) {
        i++;
    }
    if (colB[i] && colB[i].min <= aa.point) {
        colB[i].value += aa.value;
    }
    return i;
}, 0);

document.write('<pre>' + JSON.stringify(colB, 0, 4) + '</pre>');

答案 1 :(得分:0)

假设值是整数且范围合理(不太大)。

定义sums[x]从0到x的所有值的总和。从colA开始计算它。对于值colA[i] - &gt; sums [colA [i]] + = colA [i]。然后运行总和并将所有内容相加以使其与定义匹配。

现在为colB中的每个元素value = sums[max - 1] - sums[min - 1]。 (-1因为边界上的条件)。

所以现在你是O(范围+ colB + colA)(或3的最大值)。

如果范围很大,您仍然可以执行相同的操作,但首先要对值进行标准化。这是采用colA,colB.min和colB.max中的所有值排序并删除重复项,并将它们替换为已排序数组中的索引。计算结果无关紧要,但范围变为与colA + colB大小一样大的整数。

答案 2 :(得分:0)

不确定这是否有更好的时间复杂性,但它更“lodashy”:

_.map(colB, function(b) { 
    return _.defaults({ value: _(colA).filter(function(a) { 
        return a.point >= b.min && a.point < b.max; 
    }).sumBy('value') }, b);
});
  • map()返回一个新数组,包含新对象(无副作用)
  • defaults()用于将新valuecolB分配给对象。
  • filter()查找colA中符合当前colB对象的对象。
  • sumBy()根据value属性计算总和。