JavaScript 中合并数组的两种方法

发布于 2018-09-07 20:12:50 字数 3448 浏览 1872 评论 0

这是关于 JavaScript 技术快速简单的后。我们要结合/合并两个 JavaScript 数组的方法不同,以及各自的优点/缺点的方法。

让我们开始的场景:

var a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
var b = [ "foo", "bar", "baz", "bam", "bun", "fun" ];

简单的合并数组 AB 的,很明显应该是这样:

[1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]

Concat

最常见的方法是:

var c = a.concat( b );

a; // [1,2,3,4,5,6,7,8,9]
b; // ["foo","bar","baz","bam","bun","fun"]

c; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]

正如你所看到的,C 是一种全新的数组表示两者的合并数组 A 和 B 的结果,AB 两个数组本身没有变化。

如果 A 数组有 10000 项,B 数组也是 10000 个项目,那么 C 现在是 20000 项,基本上翻了一番,构成的内存使用情况 A 和 B。

也许你也想到了下面的方法,回收内存垃圾。

a = b = null; // `a` and `b` can go away now

只有几个小的数组这个方法是很好的。但是如果遇到大的数组,或是重复这一过程,经常有很多次,或工作在内存有限的环境中,它有很多不足之处。

循环插入

也许我们可以添加一个 array 的内容到其他数组里面,使用 push()

 // `b` onto `a`
for (var i=0; i < b.length; i++) {
    a.push( b[i] );
}

a; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]

b = null;

现在 A 既有原始的结果又加上了 B 内容,能更好的使用内存了。

但如果 AB 进行比较非常大的?两个内存和速度的原因,你可能会想把小 A 到前面的 B 而不是再 B 到结束 A。没问题,只是 push()unshift(..) 在相反方向的:

// `a` into `b`:
for (var i=a.length-1; i >= 0; i--) {
    b.unshift( a[i] );
}

b; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]

a = null;

功能上的技巧

for 循环是丑陋的和难以维持。我们可以做的更好吗?这是我们的第一次尝试,使用 reduce

// `b` onto `a`:
a = b.reduce( function(coll,item){
    coll.push( item );
    return coll;
}, a );

a; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]

// or `a` into `b`:
b = a.reduceRight( function(coll,item){
    coll.unshift( item );
    return coll;
}, b );

b; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]

reduce()reduceRight() 是好的,但他们有点笨拙的。ES6 => 箭头的函数将瘦身略有下降,但它仍然需要每项调用一个函数,这是不幸的。

// `b` onto `a`:
a.push.apply( a, b );

a; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]

// or `a` into `b`:
b.unshift.apply( b, a );

b; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]

这是一个正确的要好很多,特别是自从 unshift() 方法在这里并不需要担心相反的顺序在以前的尝试。将 6 的传播算子是更好的:a.push( ...b )b.unshift( ...a )

但是事情并非像玫瑰一样看起来。在这两种情况下,通过 ABapply() 第二论点(或通过 ... 传播算子)意味着阵列被分散作为函数的参数。

第一个主要的问题是,我们有效地增加一倍的大小(暂时的,当然!)这件事被添加到基本上是将其内容复制到堆栈函数调用。此外,不同的JS引擎有不同的实现依赖性的参数,可以通过数。

所以如果 array 加上有一百万项,你几乎肯定超过允许的,堆栈的push(..)unshift(..)打电话。呃。这将为几千元工作的很好,但是你必须小心,不要超过一个合理的安全限制。

注意:你可以试着同样的事情splice(..)但是,你也会有相同的结论push(..) / unshift(..)

一种选择是使用这种方法,但批了段在最大安全的大小:

function combineInto(a,b) {
    var len = a.length;
    for (var i=0; i < len; i=i+5000) {
        b.unshift.apply( b, a.slice( i, i+5000 ) );
    }
}

我们从可读性倒退(甚至表现!)。以前让我们放弃我们的收益到目前为止退出。

总结

concat(..) 是尝试和真实的方法相结合的两个(或更多!)阵列。但隐藏的危险是,它创造了一个新的数组,而不是修改一个现有的。

有选择,修改的地方,但他们有不同的权衡。

给各种的优缺点,也许是最好的所有的选项(包括其他未显示)是 reduce(..)reduceRight(..)

无论你选择什么,它批判地思考你的数组合并策略而不是想当然的可能是一个好主意。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84960 人气
更多

推荐作者

遂心如意

文章 0 评论 0

5513090242

文章 0 评论 0

巷雨优美回忆

文章 0 评论 0

junpengz2000

文章 0 评论 0

13郎

文章 0 评论 0

qq_xU4RDg

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文