问题 如何在JavaScript中合并排序的数组
我有三个排序的数组,如下所示
[{name:"a"}, {name:"b"}, {name:"m"}, {name:"x"}]
[{name:"a"}, {name:"e"}, {name:"i"}, {name:"o"}]
[{name:"g"}, {name:"h"}, {name:"m"}, {name:"n"}]
这些数组基于Array中每个对象的name属性进行排序。这是我从Java转换为合并两个排序数组的方法
function mergeSorted(a, b) {
var answer = new Array(a.length + b.length), i = 0, j = 0, k = 0;
while (i < a.length && j < b.length) {
if (a[i].name < b[j].name) {
answer[k] = a[i];
i++;
}else {
answer[k] = b[j];
j++;
}
k++;
}
while (i < a.length) {
answer[k] = a[i];
i++;
k++;
}
while (j < b.length) {
answer[k] = b[j];
j++;
k++;
}
return answer;
}
这是两个阵列的工作小提琴 http://jsfiddle.net/euRn5/。 用n个数组实现相同目标的最佳方法是什么,我脑海中的想法是一个接一个,将它与之前合并到最后一个项目合并,如n + = i stuff。这是最好的方法吗?
3984
2017-09-09 04:48
起源
答案:
更新:
看得很清楚 current_year
现在这将是:
const mergeAll = (...arrays) => arrays.reduce(mergeSorted);
原版的:
如果您感觉功能正常,这是使用reduce的理想场所。
var mergeAll = function(){
return Array.prototype.slice.call(arguments).reduce(mergeSorted);
};
例:
var a = [{name:"a"}, {name:"b"}, {name:"m"}, {name:"x"}];
var b = [{name:"a"}, {name:"e"}, {name:"i"}, {name:"o"}];
var c = [{name:"g"}, {name:"h"}, {name:"m"}, {name:"n"}];
console.log(mergeAll(a,b,c).map(function(x){return x.name;}));
的jsfiddle: http://jsfiddle.net/FeT6m/
4
2017-09-09 05:42
我相信标准和最理解的代码..
function mergeArray(arr1, arr2) {
var new_array = [];
var i = 0,
j = 0,
index = 0;
while (new_array.length != (arr1.length + arr2.length) - 1) {
if (arr1[i] < arr2[j]) {
new_array.push(arr1[i]);
i++;
} else {
new_array.push(arr2[j]);
j++;
}
}
return new_array;
}
功能调用:
var merged_array = mergeArray([1,6,9,95], [2,7,10,11,14,18]);
3
2018-05-14 11:21
更快,仅合并1次传递,具有更大的灵活性(keepDuplicates,自定义比较器):
/* mergeSortedArrays(arrays[, keepDuplicates[, comparator[, thisArg]]])
Merges multiple sorted arrays into a new sorted array.
Arguments:
- arrays: array of sorted arrays to be merged
- keepDuplicates (optional): (true/false) whether to keep duplicate values
Default: false
- comparator (optional): function used to compare values
Default: sort numbers in ascending order
Example comparator: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
- thisArg (optional): comparator is bound to thisArg when invoked
Returns: a new sorted array containing all the values from the arrays
*/
function mergeSortedArrays(arrays, keepDuplicates, comparator, thisArg) {
// Coerce to boolean to speed up testings in some javascript engines:
keepDuplicates = !!keepDuplicates;
// By default, sort numbers in ascending order:
if(!comparator) comparator = function(a, b) { return a - b; };
var nb = arrays.length, // Number of arrays to be merged
iter = new Array(nb), // Current position of iteration of each array
next = [], // Keep each array sorted by the value of their next element
length = 0; // The combined length of all arrays
// Populate iter and next:
for(var i = 0, arr; i < nb; i++) {
arr = arrays[i];
iter[i] = 0;
if(arr.length > 0) {
insertNextIndex(next, i, arr[0], comparator, thisArg);
}
length += arr.length;
}
// Insert index of array into next:
function insertNextIndex(next, index, val, comparator, thisArg) {
var i = next.length;
while(i--) { // Reverse loop...
var j = next[i];
if(comparator.call(thisArg, arrays[j][iter[j]], val) >= 0) { // ...until we find a greater value
break;
}
}
next.splice(i + 1, 0, index);
}
var merged = keepDuplicates ? new Array(length) : [],
k = 0, // Iterate over merged
min, val, lastVal;
// First iteration to get a value for lastVal (for duplicate checks):
if(!keepDuplicates && next.length > 0) {
min = next.pop();
arr = arrays[min];
i = iter[min]++;
val = arr[i];
merged[k++] = val;
lastVal = val;
if(++i < arr.length) { // If available, insert next value in next:
insertNextIndex(next, min, arr[i], comparator, thisArg);
}
}
// Merge multiple arrays:
while(next.length > 1) { // While there is still multiple arrays to be merged
min = next.pop();
arr = arrays[min];
i = iter[min]++;
val = arr[i];
if(keepDuplicates || comparator.call(thisArg, lastVal, val) !== 0) {
merged[k++] = val;
lastVal = val;
}
if(++i < arr.length) { // If available, insert next value in next:
insertNextIndex(next, min, arr[i], comparator, thisArg);
}
}
// When there remain only 1 array with unmerged values, use a faster loop:
if(next.length > 0) {
arr = arrays[next[0]];
i = iter[next[0]];
length = arr.length;
while(i < length) { // To the end
val = arr[i++];
if(keepDuplicates || comparator.call(thisArg, lastVal, val) !== 0) {
merged[k++] = val;
lastVal = val;
}
}
}
return merged;
}
在1遍中合并消除了创建需要时间和内存的中间阵列。此外,通过保持每个数组中下一个元素的排序列表,可以很好地减少比较次数(参见 next
数组)。当数组大小已知时,它们会被预先分配以防止动态重新分配(尽管这取决于您的javascript引擎)。
对于你的情况,我会这样称呼它:
mergeSortedArrays(arrays, true, function(a, b) {
return a.name < b.name ? -1 : 1;
});
注意:如果您有大量阵列,则可以使用a 二分搜索 而不是线性搜索 insertNextIndex()
。或者从使用 二进制堆 对于 next
。
3
2018-05-14 03:31
编辑 反映这一点 Exception
原来的解决方案,通过称之为扩展 mergeSorted(mergeSorted(a,b),c)
是 更快 比我的解决方案。
Javascript的内置排序不够快,你可以将所有数组连接在一起并一次性对整个事物进行排序。 Javascript是 不 有利于重新实施应该在较低级别完成的事情。
var a1 = [{name:"a"}, {name:"b"}, {name:"m"}, {name:"x"}]
var a2 = [{name:"a"}, {name:"e"}, {name:"i"}, {name:"o"}]
var a3 = [{name:"g"}, {name:"h"}, {name:"m"}, {name:"n"}]
a1.concat(a2,a3).sort(function(a,b){return (a.name>b.name)-(a.name<b.name)})
// [{name:"a"}, {name:"a"}, {name:"b"}, {name:"e"}, {name:"h"}, {name:"i"}, {name:"g"}, {name:"m"}, {name:"m"}, {name:"n"}, {name:"o"}, {name:"x"}]
2
2017-09-09 04:52
原生实现并不总是最快(正如您可能已经注意到的那样),并且由于广泛的错误检查,历史上有点迟缓。话虽如此,由于与专门为优化某些任务而专门构建的硬件或例程的更强大集成,未来可能会有性能增强。如果您编写自己的代码,那么一旦实现,您的应用程序将无法利用这些性能提升。由您来决定优势所在以及风险是什么。
无论如何,我已经为你的优化编写了一个更漂亮的优化代码版本:
function mergeSorted(a,b){
var alen = a.length
, blen = b.length
, i, j, k = j = i = 0
, answer = new Array(alen + blen)
;//var
while(i < alen && j < blen)
answer[k++] = a[i].name < b[j].name ? a[i++] : b[j++];
while(i < alen) answer[k++] = a[i++];
while(j < blen) answer[k++] = b[j++];
return answer;
}
2
2017-09-09 06:36