如何将另一个数组添加到现有的JavaScript数组中,而不创建新数组

1444

似乎没有一种方法可以将一个现有的 JavaScript 数组与另一个数组扩展,也就是模仿 Python 的 extend 方法。

我想要实现以下内容:

>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
>>> a
[1, 2, 3, 4, 5]
我知道有一个方法,但它会创建一个新的数组而不是简单地扩展第一个数组。我想要一种算法,在ab大很多时仍然能高效工作(即不复制a)。 注意: 这不是如何向数组附加内容?的重复问题--这里的目标是将一个数组的所有内容添加到另一个数组中,并且要“原地”执行此操作,即不复制扩展数组的所有元素。

10
来自@Toothbrush对一个回答的评论:“a.push(...b)”。它在概念上与最佳答案类似,但针对ES6进行了更新。 - tscizzle
a.push(...b)
- Ali NajafZadeh
20个回答

5
这个解决方案对我有效(使用 ECMAScript 6 的 spread 操作符):

let array = ['my', 'solution', 'works'];
let newArray = [];
let newArray2 = [];
newArray.push(...array); // Adding to same array
newArray2.push([...array]); // Adding as child/leaf/sub-array
console.log(newArray);
console.log(newArray2);


4

我添加了这个回答,因为尽管问题明确表示不创建新的数组,但是几乎所有的答案都忽略了这一点。

现代JavaScript可以很好地处理作为可迭代对象的数组等。这使得可以实现一个版本的concat方法,它建立在此基础上,并将数组数据逻辑地跨越其参数。

下面的示例使用了iter-ops库中具有此逻辑的特性:

import {pipe, concat} from 'iter-ops';

const i = pipe(
    originalArray,
    concat(array2, array3, array4, ...)
); //=> Iterable

for(const a of i) {
    console.log(a); // iterate over values from all arrays
}

上面的代码中没有创建新的数组。操作符concat将遍历原始数组,然后按照指定顺序自动地继续遍历array2array3等。

这是在内存使用方面连接数组最高效的方式。

如果最后你决定将其转换成实际的物理数组,你可以通过扩展运算符或Array.from来实现:

const fullArray1 = [...i]; // pulls all values from iterable, into a new array

const fullArray2 = Array.from(i); // does the same

0

合并两个以上数组的另一种解决方案

var a = [1, 2],
    b = [3, 4, 5],
    c = [6, 7];

// Merge the contents of multiple arrays together into the first array
var mergeArrays = function() {
 var i, len = arguments.length;
 if (len > 1) {
  for (i = 1; i < len; i++) {
    arguments[0].push.apply(arguments[0], arguments[i]);
  }
 }
};

然后调用并打印如下:

mergeArrays(a, b, c);
console.log(a)

输出将是:数组 [1, 2, 3, 4, 5, 6, 7]


0

将答案合并...

Array.prototype.extend = function(array) {
    if (array.length < 150000) {
        this.push.apply(this, array)
    } else {
        for (var i = 0, len = array.length; i < len; ++i) {
            this.push(array[i]);
        };
    }  
}

13
不需要这样做。使用forEach的for循环比使用push.apply更快,并且无论要扩展的数组长度是多少,都可以使用此方法。请查看我修改后的回答:https://dev59.com/VnM_5IYBdhLWcg3wcSx_#17368101无论如何,你怎么知道150000是所有浏览器都适用的正确数字?这是一个虚假数据。 - jcdude
哈哈,我的答案无法识别,但似乎是当时找到的其他答案的组合 - 即摘要。不用担心。 - zCoder

0
你可以像下面这样为extend创建一个polyfill。它会原地添加到数组并返回自身,这样你就可以链接其他方法。

if (Array.prototype.extend === undefined) {
  Array.prototype.extend = function(other) {
    this.push.apply(this, arguments.length > 1 ? arguments : other);
    return this;
  };
}

function print() {
  document.body.innerHTML += [].map.call(arguments, function(item) {
    return typeof item === 'object' ? JSON.stringify(item) : item;
  }).join(' ') + '\n';
}
document.body.innerHTML = '';

var a = [1, 2, 3];
var b = [4, 5, 6];

print('Concat');
print('(1)', a.concat(b));
print('(2)', a.concat(b));
print('(3)', a.concat(4, 5, 6));

print('\nExtend');
print('(1)', a.extend(b));
print('(2)', a.extend(b));
print('(3)', a.extend(4, 5, 6));
body {
  font-family: monospace;
  white-space: pre;
}


-2

答案非常简单。

>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
(The following code will combine the two arrays.)

a = a.concat(b);

>>> a
[1, 2, 3, 4, 5]

Concat函数与JavaScript字符串连接非常相似。它将返回一个由您放入concat函数的参数组合在调用该函数的数组末尾的结果。关键是您必须将返回值分配给变量,否则它会丢失。例如:

a.concat(b);  <--- This does absolutely nothing since it is just returning the combined arrays, but it doesn't do anything with it.

2
正如在MDN的“Array.prototype.concat()”文档中清楚地说明的那样,它将返回一个新数组,而不是像OP所明确要求的那样附加到现有数组中。 - Wilt

-2

另外一个选项,如果您已经安装了lodash:

 import { merge } from 'lodash';

 var arr1 = merge(arr1, arr2);

我认为这种方法不适用于这样的数组。请提供一个可行的代码片段链接。 - Dzinx

-3

你可以通过使用push()方法向数组中简单地添加新元素来实现。

let colors = ["Red", "Blue", "Orange"];
console.log('Array before push: ' + colors);
// append new value to the array
colors.push("Green");
console.log('Array after push : ' + colors);

另一种将元素添加到数组开头的方法是使用unshift()函数,它会添加并返回新长度。它接受多个参数,附加现有元素的索引,最后返回数组的新长度:

let colors = ["Red", "Blue", "Orange"];
console.log('Array before unshift: ' + colors);
// append new value to the array
colors.unshift("Black", "Green");
console.log('Array after unshift : ' + colors);

还有其他方法。您可以在这里查看它们。


2
这将一个值添加到数组中。它不像问题描述的那样在原地将一个数组添加到另一个数组中,也不像 Python 的列表 extend 方法那样。 - Hans Bouwmeester

-3

当处理超过150,000条记录时,请使用Array.extend而不是Array.push

if (!Array.prototype.extend) {
  Array.prototype.extend = function(arr) {
    if (!Array.isArray(arr)) {
      return this;
    }

    for (let record of arr) {
      this.push(record);
    }

    return this;
  };
}

-9

非常简单,不依赖于展开运算符或 apply,如果这是一个问题。

b.map(x => a.push(x));

在运行了一些性能测试之后,发现这个程序非常慢,但是它回答了关于不创建新数组的问题。Concat要快得多,甚至jQuery的$.merge()也要比它快。

https://jsperf.com/merge-arrays19b/1


6
如果你不需要使用返回值的话,建议使用 .forEach 而不是 .map。这样更能清晰地表达你代码的意图。 - david
6
这不是个人喜好的问题。这些“功能性”方法各自有特定的含义。在这里调用.map看起来非常奇怪。就像调用 b.filter(x => a.push(x))一样。虽然它能工作,但会让读者产生混淆,因为它暗示了某些事情正在发生,而实际上并没有。 - david
不值得我浪费时间去辩论。它可以工作。我指出了性能问题。如果你觉得它看起来奇怪,就不要使用它。 - elPastor
3
@elPastor 这个值得你花时间去做,因为像我这样的人会坐着挠脖子想知道你的代码中还有些什么他看不到的东西。在大多数情况下,意图的清晰比性能更重要。请尊重阅读你代码的人的时间,因为当你只是一个人时,他们可能会很多。谢谢。 - Dmytro Y.
2
@elPastor 我非常清楚 .map() 的作用,这也是问题所在。这个知识会让我认为你需要结果数组,否则使用 .forEach() 会更好,因为它可以让读者注意回调函数的副作用。严格来说,你的解决方案创建了一个额外的自然数数组(push 的结果),而问题陈述是:“不创建新数组”。 - Dmytro Y.
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接