[英]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);
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
”为新数组:
push
the current item on to the combined
array.如果这是第一遍或最后一个项目与当前项目不重叠,则将当前项目push
送到combined
数组。pop
the last item off the combined
array.从combined
数组中pop
最后一项。push
the combination of the last item and the current item on to the combined
array. push
到最后一个项目和当前项的组合combined
阵列。Simple concise JavaScript solution:简单简洁的 JavaScript 解决方案:
Algo算法
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.