JavaScript学习笔记:数组合并

发布于 大漠

JavaScript中数组知识点很多,前面学习了一些基础知识。那么今天继续学习数组相关的知识。这篇文章主要是看在JavaScript中如何合并数组。

合并数组是一个相当常见,在实际使用的场景也有不同之处。比如说,我们有两个变量:

arr1 = [1,2];
arr2 = [3,4];

将数组arr1arr2合并成一个数组arr

arr = [1,2,3,4]

另外还有一种方式是将一个复合数组的数组项合并在一起,比如:

var myArray = [[1, 2],[3, 4, 5], [6, 7, 8, 9]];

将数组myArray的数组项合并在一起,变成想要的效果:

arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]

将多个数组合并成一个数组

我们先来考虑下面的这种情况,我们有两个(或多个)数组:

var arr1 = [1,2];
var arr2 = [3,4];

想要的结果是将arr1arr2合并在一起,最终想要的结果是:[1,2,3,4]。实现这样的效果,在JavaScript中有很多种,接下来看看各种实现方法。

Array.prototype.concat()方法

在JavaScript中Array.prototype.concat()方法可以传入的数组或非数组与原数组合并,并组成一个新数组再返回

如此一来就可以这样做:

var arr1 = [1,2];
var arr2 = [3,4];
var arr = arr1.concat(arr2);
console.log(arr); // [1, 2, 3, 4]

将上面的代码封装到一个函数中,比如:

function flatten (arr1, arr2) {
    return arr1.concat(arr2);
}
flatten(arr1,arr2); // [1, 2, 3, 4]

正如你看到的,返回的结果是一个全新的数组,将数组arr1arr2合并在一起,并且arr1arr2不会有任何变化。是不是很简单。

不过这种方法将会有所限制,如果arr1arr2数组元素都很多的话或者说内存有限的系统中经常重复这个过程,它其实还有很多改进的地方。

for循环和Array.prototype.push()方法

其实还可以使用for循环和Array.prototype.push()方法,将一个数组的内容复制到另一个。

function flatten (arr1, arr2) {
    for (var i = 0; i < arr2.length; i++) {
        arr1.push(arr2[i]);
    }
    return arr1;
}

上面的方法将数组arr2中的每个元素复制到数组arr1中。现在数组arr1中有了数组arr2的元素。

有个小细节,如果数组arr1arr2相比,数组arr1中的元素数量小于数组arr2时,出于内存和速度的原因,可以将更小的数组arr1放到数组arr2前面。在JavaScript中只需要将Array.prototype.push()方法换成Array.prototype.unshift()方法。

function flatten (arr1,arr2) {
    for (var i = arr1.length - 1; i >= 0; i--) {
        arr2.unshift(arr1[i]);
    }
    return arr2;
}

他们得到的结果都将是一样的。

数组的reduce()或reduceRight()方法

使用for循环看上去很丑而且又不好维护,其实使用Array.prototype.reduce()Array.prototype.reduceRight()可以做得更好:

function flatten (arr1, arr2) {
    return arr2.reduce(function(prev, curr){
        prev.push(curr);
        return prev;
    },arr1);
}

或者

function flatten(arr1, arr2){
    return arr1.reduceRight( function (prev, curr){
        prev.unshift(curr);
        return prev;
    },arr2);
}

上面这些方法都实现了想要的结果。但他们都有不同的限制,比如使用push()unshift()reduce()reduceRight()只能针对两个数组合并,如果要将两个以上数组合并,就困难了。不过concat()方法可以将多个数组合并在一起。

有时候将两个或多个数组合并在一起的时候,还需要对合并后的相同的数组元素删除(数组去重)。在合并后的数组之后,再做一下数组去重,即可达到数组去重的效果:

function flatten(arr1,arr2){
    var result = [];
    var arr = [];

    arr = arr2.reduce(function(prev, curr){
        prev.push(curr);
        return prev;
    },arr1);
    
    for (var i = 0; i < arr.length; i++) {
        var index = arr[i];
        if (result.indexOf(index) === -1) {
            result.push(index);
        }
    }
    return result;
}
flatten([1,2],[12,1,2,3,4]); // [1, 2, 12, 3, 4]

将复合数组合并成一个数组

接下来看另外一种数组合并情形。首先有一个复合数组:

var myArray = [[1, 2],[3, 4, 5], [6, 7, 8, 9]];

现在想要做的就是将数组myArray中的子数组的数组项合并在一起,变成一个新数组:[1, 2, 3, 4, 5, 6, 7, 8, 9]。接下来看看怎么实现这样的数组合并效果。

Array.prototype.push()方法

先来看一个简单的方法,就是通过for循环和Array.prototype.push()方法实现。

function flatten(arr) {
    var result = [];
    for (var i = 0; i < arr.length; i++) {
        for (var j = 0; j< arr[i].length; j++) {
            result.push(arr[i][j]);
        }
    }
    return result;
}
flatten([[1, 2],[3, 4, 5], [6, 7, 8, 9]]); //[1, 2, 3, 4, 5, 6, 7, 8, 9]

不过上面的方法:

flatten([[1, 2],[3, 4, 5], [6, 7, 8, 9],10]);

返回的值仍然是:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

而不是想要的:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

要完成上面的效果可以做一下改造:

function flatten(a, r) {
    if (!r) {
        r = [];
    }
    for (var i = 0; i < a.length; i++) {
        if (a[i].constructor == Array) {
            flatten(a[i], r);
        } else {
            r.push(a[i]);
        }
    }
    return r;
}
flatten([[1, 2],[3, 4, 5], [6, 7, 8, 9,[11,12,[12,13,[14]]]],10]);
// =>[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 12, 13, 14, 10]

Array.prototype.concat()

除了push()方法,在JavaScript中可以使用Array.prototype.concat()方法来实现:

function flatten(arr){
    var result = [];
    for (var i = 0; i < arr.length; i++) {
        result = result.concat(arr[i]);
    }
    return result;
}
flatten([[1, 2],[3, 4, 5], [6, 7, 8, 9]]);//[1, 2, 3, 4, 5, 6, 7, 8, 9]
flatten([[1, 2],[3, 4, 5], [6, 7, 8, 9],10,11]);//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

不过可以通过Function.prototype.apply()方法,让其变得更简单:

function flatten (arr) {
    return Array.prototype.concat.apply([], arr);
}

还可以将上面的方法做个精简:

function flatten (arr) {
    return [].concat.apply([],arr);
}

在ES6中,还可以这样写:

function flatten(arr) {
    return [].concat(...arr)
}

另外让自己的代码变得更健壮,还可以添加一些判断:

function flatten(arr) {
    arr = Array.prototype.concat.apply([], arr);
    return arr.some(Array.isArray) ? flatten(arr) : arr;
}

这样写,还可以实现三重或者更多重的数组合并:

flatten([[1, 2],[3, 4, 5], [6, 7, 8, 9,[11,12,[12]]],10]);
// =>[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 12, 10]
flatten([[1, 2],[3, 4, 5], [6, 7, 8, 9,[11,12,[13]]],10]);
// =>[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 10]

或者:

function flatten (arr) {
    var isArray = Object.prototype.toString.call(arr) === '[object Array]';
    if (isArray && arr.length > 0) {
        var head = arr[0];
        var tail = arr.slice(1);
        return flatten(head).concat(flatten(tail));
    } else {
        return [].concat(arr);
    }
}

Array.prototype.reduce()

同样的,还可以使用Array.prototype.reduce()来实现同样的效果:

function flatten(arr) {
    return arr.reduce(function(flat, toFlatten) {
        return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
    }, []);
}
flatten([[1, 2],[3, 4, 5], [6, 7, 8, 9]]);
// => [1, 2, 3, 4, 5, 6, 7, 8, 9]
flatten([[1, 2],[3, 4, 5], [6, 7, 8, 9,[10]]]);
// => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

ES6方法

使用ES6方法:

function flatten(arr) {
    return [].concat(...arr)
}

除了上面这种方法,还可以这样:

function deepFlatten(arr) {
    return flatten( // return shalowly flattened array
        arr.map(x => // with each x in array
            Array.isArray(x) // is x an array?
            ? deepFlatten(x) // if yes, return deeply flattened x
            : x // if no, return just x
        )
    )
}

在上面的几种方法中,添加一些去重的代码,也可以很快实现。

function flatten(arr) {
    var newArr = arr.reduce(function(flat, toFlatten) {
        return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
    }, []);
    var result;
    result = newArr.filter(function (ele,i,arr) {
        return newArr.indexOf(ele) === i;
    });
    return result;
}
flatten([[1, 2],[3, 4, 5], [6, 7, 8, 9,[10,[12]]],11]);
// => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 11]
flatten([[1, 2],[3, 4, 5,[1,2,3,4,5]], [6, 7, 8, 9,[10,[12]]],11]);
// => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 11]

有关于更多的数组去重方法,可以阅读《JavaScript学习笔记:数组去重》一文。

扩展阅读

总结

这篇文章主要介绍了在JavaScript中通过push()concat()reduce()等方法的组合,实现数组合并的功能。并且在此基础上结合《JavaScript学习笔记:数组去重》一文介绍的方法,还可以轻松的实现合并后的数组,把重复的数组项删除。

如果文中有不对之处或者你有更好的方案,欢迎在下面的评论中与我们一起分享。

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。中国Drupal社区核心成员之一。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/javascript/merge-flatten-an-array-of-arrays-in-javascript.htmlZoom Lebron XI 11