JavaScript如何优雅地合并和排序两个数组

313 阅读3分钟

在JavaScript的编程世界中,合并和排序数组是一个重要但常被忽视的细节。如何优雅地通过不同的方法合并两个数组,并且确保最后合并的结果是有序的。同时,我们会讨论每种方法的优点和缺。

一、合并两个JavaScript数组的方法

在JavaScript中,存在多种合并数组的方式。以下,我们将讨论三种最常见的方法: concat(),push.apply(),以及ES6的扩展运算符

  • 使用concat()方法

concat()方法用于连接两个或者多个数组。该方法不会改变现有的数组,而是返回一个全新的数组。

var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
var arr3 = arr1.concat(arr2); // 输出 [1, 2, 3, 4, 5, 6]

优点:代码简洁,易于理解,并且兼容所有JavaScript环境。

缺点:当处理大型数组时,性能较低,因为每次使用concat(),JavaScript都需要创建一个新数组。

  • 使用push.apply()方法

push.apply()函数的作用是将第二个数组的所有元素都添加到第一个数组的尾部。

var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
Array.prototype.push.apply(arr1, arr2); // arr1 输出 [1, 2, 3, 4, 5, 6]

优点:相比concat()push.apply()的性能较好,尤其在不需要保持原始数组不变的情况下。

缺点:push.apply()会改变原始数组。如果在某些情况下,需要保持原始数组不变,那么使用这种方法就需要格外小心。

  • 使用ES6的扩展运算符

扩展运算符是ES6新引入的特性,可以很方便地合并数组。

javascriptCopy code
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
arr1 = [...arr1, ...arr2]; // arr1 输出 [1, 2, 3, 4, 5, 6]

优点:代码简洁易读。

缺点:浏览器兼容性问题,不是所有的浏览器和JavaScript环境都支持ES6。

二、合并两个有序数组并保持结果数组有序

如果待合并的两个数组都是有序数组,并且需要合并后的数组也是有序的,那么我们可以利用有序数组的特性进行优化。这就引出了“归并”技术,常用于归并排序中。

我们可以通过双指针法,一个指针指向arr1的开头,一个指针指向arr2的开头。每次都将较小的元素放入结果数组中,并移动指向较小元素的指针,直到其中一个指针超出数组长度。最后,如果另一个数组还有元素,就直接把剩下元素都放入结果数组中。

这种方法的时间复杂度为O(n)。

示例:

jsCopy code
function mergeSortedArrays(arr1, arr2){
    let res = []; 
    let i = 0; 
    let j = 0;

    while(i < arr1.length && j < arr2.length) {
        if(arr1[i] < arr2[j]) {
            res.push(arr1[i]);
            i++;
        } else {
            res.push(arr2[j]);
            j++;
        }
    }

    while(i < arr1.length) {
        res.push(arr1[i]);
        i++;
    }

    while(j < arr2.length) {
        res.push(arr2[j]);
        j++;
    }

    return res;
}

let arr1 = [1,2,3];
let arr2 = [4,5,6];
console.log(mergeSortedArrays(arr1,arr2)); // 输出 [1,2,3,4,5,6]

同样,这种方法也适用于ES6,我们可以使用扩展运算符将剩余元素加入结果数组。

优化后的ES6版本:

jsCopy code
function mergeSortedArrays(arr1, arr2){
    let res = []; 
    let i = 0; 
    let j = 0;

    while(i < arr1.length && j < arr2.length) {
        if(arr1[i] < arr2[j]) {
            res.push(arr1[i]);
            i++;
        } else {
            res.push(arr2[j]);
            j++;
        }
    }

    return res.concat(arr1.slice(i)).concat(arr2.slice(j));
}

let arr1 = [1,2,3];
let arr2 = [4,5,6];
console.log(mergeSortedArrays(arr1,arr2)); // 输出 [1,2,3,4,5,6]

在这个版本中,我们利用了ES6的slice和concat方法,如果某个数组还有剩余元素,我们就直接将剩余部分整体加入结果数组。因为这些元素本身已经有序,所以这样做没有问题。