简体   繁体   English

合并具有重叠值的数组

[英]Merge arrays with overlapping values

Im using Node.js.我正在使用 Node.js。 (...and underscore.js) (...和 underscore.js)

Consider this data structure考虑这个数据结构

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

numbers contain arrays that always contain number pairs. numbers包含始终包含数字对的数组。 Think of these number pairs as "start" and "end".将这些数字对视为“开始”和“结束”。 I want a function that takes numbers as argument, and loop trough its content, and if the "start" number of a pair overlap the "end" number of previous pair, these arrays is merged into one.我想要一个将numbers作为参数并循环遍历其内容的函数,如果一对的“开始”数字与前一对的“结束”数字重叠,则这些数组将合并为一个。 For example this:例如这个:

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

Becomes this:变成这样:

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

Actually, I already have written a function for this that works fine, but feels a bit clunky.实际上,我已经为此编写了一个功能,它运行良好,但感觉有点笨拙。

I'm curious if some javascript wizard can dazzle me with a super elegant solution =).我很好奇是否有一些 javascript 向导可以用超级优雅的解决方案让我眼花缭乱 =)。

Create an empty "result" array.创建一个空的“结果”数组。 Loop over the ranges array and either change the last item of the result or add the current range to it.循环遍历 range 数组并更改结果的最后一项或将当前范围添加到其中。

 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)));

This assumes that the source array is sorted, if it's not always the case, sort it before merging:这假设源数组已排序,如果情况并非总是如此,请在合并之前对其进行排序:

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

I created a function which does what you want:我创建了一个可以执行您想要的功能的函数:

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;
};

This function can be used this way:这个函数可以这样使用:

var mergedNumbers = merge(numbers);


DEMO演示

As @Brett said, this might be a better fit for Code Review (just be sure to include your current implementation).正如@Brett 所说,这可能更适合代码审查(只需确保包含您当前的实现)。 If you post there, put a reference to it here somewhere and I'll move my answer.如果您在那里发帖,请在此处的某处引用它,我会移动我的答案。


Assuming that your numbers array is already sorted correctly, this function should do what you want:假设你的numbers数组已经正确排序,这个函数应该做你想要的:

 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>');

This " reduce s" the original array to the new one using the following logic in the reduce function:使用reduce函数中的以下逻辑将原始数组“ reduce ”为新数组:

  1. If this is the first pass or the last item does not overlap the current item, push the current item on to the combined array.如果这是第一遍或最后一个项目与当前项目不重叠,则将当前项目push送到combined数组。
  2. Otherwise:除此以外:
    1. pop the last item off the combined array.combined数组中pop最后一项。
    2. push the combination of the last item and the current item on to the combined array. push到最后一个项目和当前项的组合combined阵列。

Simple concise JavaScript solution:简单简洁的 JavaScript 解决方案:

Algo算法

  1. Sort the intervals by the start index in ascending order.按开始索引按升序对间隔进行排序。
  2. If the current interval overlap with the previous one, update the previous interval accordingly.如果当前间隔与前一个间隔重叠,则相应地更新前一个间隔。
  3. Otherwise, if the current start value > the previous end value), we put the interval in the result.否则,如果当前起始值 > 前一个结束值),我们将间隔放入结果中。

Implement code实现代码

 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]]));

let arr = [
  [1, 3],
  [2, 6],
  [5, 10],
  [15, 18],
  [18, 6],
];

const mergeoverlapping = (arr) => {
  if (arr.length < 2) return intervals;
  arr.sort((a, b) => a[0] - b[0]);
  let top = 0;
  let down = arr.length - 1;
  let left = 0;
  let temp = [];
  let right = arr[0].length - 1;
  let result = [];
  while (top + 1 <= down) {
    if (arr[top][right] >= arr[top + 1][left]) {
      arr[top + 1][left] = arr[top][left];
      temp = [arr[top + 1][left], arr[top + 1][right]];
    } else {
      result.push(temp);
      temp = arr[top + 1];
    }
    top++;
  }
  result.push(temp);
  console.log(result);
};

console.log(mergeoverlapping(arr));

Expanding on accepted solution to provide more readability and a common use-case which is working with sets of integers where we want [[0,21],[22,42]] => [[0,42]]`:扩展已接受的解决方案以提供更多可读性和常见用例,该用例使用我们想要[[0,21],[22,42]] => [[0,42]]` 的整数集:

 const arr = [[21,21],[-21,1],[21,42],[5,10],[11,21]].sort((a, b) => a[0] - b[0]); print(merge(arr)); print(merge(arr, true)); function merge(ranges, integers) { // range must be sorted by 1st element let prev = ranges[0]; const result = [prev]; for (let i = 1; i < ranges.length; i++) { const next = ranges[i]; if (next[0] > prev[1] + (integers? 1: 0)) { result.push((prev = next)); continue; } if (next[1] > prev[1]) prev[1] = next[1]; } return result; } function print(value) { console.info(JSON.stringify(value)) }

Previous solutions are for closed intervals/ranges (where boundaries are included).以前的解决方案适用于封闭区间/范围(包括边界)。 This would be the approach for open intervals/ranges (boundaries not included):这将是开放区间/范围(不包括边界)的方法:

 const arr = [[21,21],[-21,1],[21,42],[5,10],[11,21]].filter(([a,b]) => a.== b),sort((a; b) => a[0] - b[0]); // 21 is not included print(merge(arr)); function merge(ranges) { // range must be sorted by 1st element let prev = ranges[0]; const result = [prev]; for (let i = 1. i < ranges;length; i++) { const next = ranges[i]. if (next[0] >= prev[1]) { // >= instead of > result;push((prev = next)); continue; } if (next[1] > prev[1]) prev[1] = next[1]; } return result. } function print(value) { console.info(JSON.stringify(value)) }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM