Javascript 在一个排序数组中合并多个预排序数组的最快方法

Javascript 在一个排序数组中合并多个预排序数组的最快方法,javascript,Javascript,我正在寻找最快的方法将多个预排序数组合并到一个排序数组中,而无需重复 例如: const arrays = [ [15, 30, 35, 40, 45, 50], [33, 36, 39, 42, 45, 48], [37, 38, 39, 40, 41, 42] ]; 应输出: [15, 30, 33, 35, 36, 37, 38, 39, 40, 41, 42, 45, 48, 50] 实际上,这些阵列要大得多,所以我正在寻找一种快速的方法来实现这一点 这个问题

我正在寻找最快的方法将多个预排序数组合并到一个排序数组中,而无需重复

例如:

const arrays = [
    [15, 30, 35, 40, 45, 50],
    [33, 36, 39, 42, 45, 48],
    [37, 38, 39, 40, 41, 42]
];
应输出:

[15, 30, 33, 35, 36, 37, 38, 39, 40, 41, 42, 45, 48, 50]
实际上,这些阵列要大得多,所以我正在寻找一种快速的方法来实现这一点


这个问题是关于性能的,我知道它可以用O(n log(n))中的concat和sort(n log(n))来完成,但是我正在寻找O(n)中未经测试的东西。我不认为我的代码是最优的,但我目前还没有找到更好的方法

进一步的小改进可能是:

  • 对循环使用普通的
    ,而不是数组.prototype.reduce
  • 删除达到“完成”状态的阵列(而不是将其标记为完成)

console.time(“创建数组”);
const arrays=Array.from({length:1000},({,row)=>{
返回数组。from({length:100000},({,i)=>row+i);
});
console.timeEnd(“创建数组”);
常量createMergedArray=(数组)=>{
控制台时间(“创建toProcess”);
const toProcess=arrays.map((数组,行)=>{
返回{done:false,行,列:0,数组};
});
console.timeEnd(“创建toProcess”);
const merged=[];
while(toProcess.some({done}=>!done)){
const scan=toProcess.reduce(
(附件,项目)=>{
如果(!item.done){
if(项目数组[项目列]<附件最小值){
acc.minimum=项目数组[项目列];
acc.rows=[项目行];
}else if(item.array[item.column]==附件最小值){
附件行推送(项目行);
}
}
返回acc;
},
{行:[],最小值:无穷大}
);
合并。推送(扫描。最小值);
scan.rows.forEach((row)=>{
const item=toProcess[行];
while(item.array[item.column]==扫描.最小值){
++项目.栏;
}
item.done=item.array.length==item.column;
});
}
返回合并;
};
控制台。时间(“合并”);
const merged=createMergedArray(数组);
控制台。时间结束(“合并”);
console.assert(
合并的.every((n,i,arr)=>n>arr[i-1]| | 0==i),
“未排序或发现重复项”
);
您没有提到数组的大小,所以我使用了1k行和100k列

如果您将数组(
number[][]
)传递给
createMergedArray
,它将为您提供:

  • 按升序排序的唯一数字数组
  • 了解这种方法是否适合您的数据大小
或者使用PHP在服务器端进行操作。那样很容易。
console.time("Creation of arrays");
const arrays = Array.from({ length: 1000 }, (_, row) => {
  return Array.from({ length: 100000 }, (_, i) => row + i);
});
console.timeEnd("Creation of arrays");

const createMergedArray = (arrays) => {
  console.time("Creation of toProcess");
  const toProcess = arrays.map((array, row) => {
    return { done: false, row, column: 0, array };
  });
  console.timeEnd("Creation of toProcess");

  const merged = [];

  while (toProcess.some(({ done }) => !done)) {
    const scan = toProcess.reduce(
      (acc, item) => {
        if (!item.done) {
          if (item.array[item.column] < acc.minimum) {
            acc.minimum = item.array[item.column];
            acc.rows = [item.row];
          } else if (item.array[item.column] === acc.minimum) {
            acc.rows.push(item.row);
          }
        }
        return acc;
      },
      { rows: [], minimum: Infinity }
    );

    merged.push(scan.minimum);

    scan.rows.forEach((row) => {
      const item = toProcess[row];
      while (item.array[item.column] === scan.minimum) {
        ++item.column;
      }
      item.done = item.array.length === item.column;
    });
  }

  return merged;
};

console.time("Merging");
const merged = createMergedArray(arrays);
console.timeEnd("Merging");

console.assert(
  merged.every((n, i, arr) => n > arr[i - 1] || 0 === i),
  "Unsorted or duplicates found"
);