合并具有重叠值的数组

时间:2014-10-15 19:53:24

标签: javascript node.js

我正在使用Node.js. (...和underscore.js)

考虑这个数据结构

var numbers = [
  [10, 20]
  [30, 40]
  [40, 50]
  [45, 70]
  ... //Possibly more arrays (always contains two numbers)
]

numbers包含始终包含数字对的数组。将这些数字对视为" start"和"结束"。我想要一个以numbers为参数的函数,并循环其内容,如果" start"一对的数字重叠"结束"前一对的数量,这些数组合并为一个。例如:

var numbers = [
  [10, 20]
  [19, 40]
  [40, 60]
  [70, 80]
]

成为这个:

var numbers = [
  [10, 60] // First, second and third array is merged because of overlapping . 
  [70, 80]
]

实际上,我已经为此编写了一个功能正常的功能,但感觉有点笨重。

我很好奇,如果一些javascript向导可以用超级优雅的解决方案让我眼花缭乱=)。

4 个答案:

答案 0 :(得分:7)

创建一个空的“result”数组。循环遍历范围数组,并更改结果的最后一项或向其添加当前范围。

function merge(ranges) {
    var result = [], last;

    ranges.forEach(function (r) {
        if (!last || r[0] > last[1])
            result.push(last = r);
        else if (r[1] > last[1])
            last[1] = r[1];
    });

    return result;
}

r = [[10, 20], [19, 40], [40, 60], [70, 80]];
document.write(JSON.stringify(merge(r)));

这假设源数组已排序,如果情况并非总是如此,请在合并前对其进行排序:

ranges.sort(function(a, b) { return a[0]-b[0] || a[1]-b[1] });

答案 1 :(得分:5)

我创建了一个能够完成你想要的功能:

function merge(arr) {
    // copy and sort the array
    var result = arr.slice().sort(function(a, b) {
            return a[0] > b[0];
        }),
        i = 0;

    while(i < result.length - 1) {
        var current = result[i],
            next = result[i+1];

        // check if there is an overlapping
        if(current[1] >= next[0]) {
            current[1] = Math.max(current[1], next[1]);
            // remove next
            result.splice(i+1, 1);
        } else {
            // move to next
            i++;
        }
    }
    return result;
};

此功能可以这种方式使用:

var mergedNumbers = merge(numbers);


DEMO

答案 2 :(得分:2)

正如@Brett所说,这可能更适合Code Review(只需确保包含您当前的实现)。如果您在那里发帖,请在某处提及它,我会移动我的答案。


假设您的numbers数组已经正确排序,此函数应该可以执行您想要的操作:

&#13;
&#13;
function combine(numbers) {
    return numbers.reduce(function(combined, next) {
        if (!combined.length || combined[combined.length-1][1] < next[0]) combined.push(next);
        else {
            var prev = combined.pop();
            combined.push([prev[0], Math.max(prev[1], next[1])]);
        }
    	return combined;
    }, []);
}		

var n = [[10, 20], [19, 40], [40, 60], [70, 80], [75, 76]];
var r = combine(n);
document.write('<pre>' + JSON.stringify(r) + '</pre>');
&#13;
&#13;
&#13;

这&#34; reduce s&#34;使用reduce函数中的以下逻辑将原始数组添加到新数组:

  1. 如果这是第一次传递或最后一项与当前项不重叠,push当前项目将传递到combined数组。
  2. 否则:
    1. pop combined数组中的最后一项。
    2. push最后一项和当前项目的组合到combined数组。

答案 3 :(得分:1)

简单简洁的 JavaScript 解决方案:

算法

  1. 按起始索引升序对区间进行排序。
  2. 如果当前间隔与前一个间隔重叠,则相应地更新前一个间隔。
  3. 否则,如果当前起始值 > 前一个结束值),我们将间隔放入结果中。

实现代码

var merge = (intervals) => {
  intervals.sort((a, b) => a[0] - b[0]);
  const merged = [intervals[0]];

  for (let i = 1; i < intervals.length; i++) {
    const [start, end] = intervals[i];
    let prev = merged[merged.length - 1];
    if (prev[1] >= start) {
      prev[1] = Math.max(prev[1], end);
    } else merged.push(intervals[i]);
  }
  return merged;
};

console.log(merge([[10, 20], [19, 40], [40, 60], [70, 80]]));