代码之家  ›  专栏  ›  技术社区  ›  Dzinx

如何用另一个数组扩展现有的javascript数组,而不创建新的数组

  •  781
  • Dzinx  · 技术社区  · 15 年前

    似乎没有一种方法可以用另一个数组扩展现有的javascript数组,即模拟python的 extend 方法。

    我希望实现以下目标:

    >>> a = [1, 2]
    [1, 2]
    >>> b = [3, 4, 5]
    [3, 4, 5]
    >>> SOMETHING HERE
    >>> a
    [1, 2, 3, 4, 5]
    

    我知道有一个 a.concat(b) 方法,但它创建了一个新数组,而不是简单地扩展第一个数组。我想要一个在 a 明显大于 b (即不复制的 )

    注: 这是 不是的副本 How to append something to an array? --这里的目标是将一个数组的全部内容添加到另一个数组中,并“就地”执行,即不复制扩展数组的所有元素。

    16 回复  |  直到 5 年前
        1
  •  1193
  •   Dzinx    5 年前

    这个 .push 方法可以接受多个参数。您可以使用 spread operator 将第二个数组的所有元素作为参数传递给 :

    >>> a.push(...b)
    

    如果您的浏览器不支持ECMAScript 6,则可以使用 .apply 而是:

    >>> a.push.apply(a, b)
    

    或者,如果你觉得更清楚的话:

    >>> Array.prototype.push.apply(a,b)
    

    请注意,如果数组 b 太长(根据浏览器的不同,问题从大约100000个元素开始)。如果你不能保证 如果足够短,您应该使用另一个答案中描述的基于标准循环的技术。

        2
  •  222
  •   Dan Dascalescu    6 年前

    2018年更新 : A better answer is a newer one of mine : a.push(...b) .不要再对这个问题投反对票了,因为它从来没有真正回答过这个问题,但这是一个2015年的黑客攻击,关于谷歌的第一次点击:)


    对于那些简单搜索“javascript数组扩展”并到达这里的用户,您可以很好地使用 Array.concat .

    var a = [1, 2, 3];
    a = a.concat([5, 4, 3]);
    

    concat将返回新数组的副本,因为线程启动程序不需要。但是你可能不在乎(当然对于大多数用途来说,这是可以的)。


    还有一些很好的ecmascript 6糖,以spread operator的形式:

    const a = [1, 2, 3];
    const b = [...a, 5, 4, 3];
    

    (它也复制。)

        3
  •  184
  •   Peter Mortensen rohan kamat    6 年前

    您应该使用基于循环的技术。此页上基于使用的其他答案 .apply 对于大型阵列,可能会失败。

    一个相当简单的基于循环的实现是:

    Array.prototype.extend = function (other_array) {
        /* You should include a test to check whether other_array really is an array */
        other_array.forEach(function(v) {this.push(v)}, this);
    }
    

    然后可以执行以下操作:

    var a = [1,2,3];
    var b = [5,4,3];
    a.extend(b);
    

    DzinX's answer (使用push.apply)和其他 应用 当我们要附加的数组很大时,基于的方法会失败(测试表明,对于我来说,Chrome大约有150000个条目,而Firefox大约有500000个条目)。您可以看到此错误发生在 this jsperf .

    当以大数组作为第二个参数调用“function.prototype.apply”时,由于超出了调用堆栈大小,因此发生错误。(MDN注意到使用 Function.prototype.apply -请参见标题为“应用和内置函数”的部分。)

    要与此页面上的其他答案进行速度比较,请查看 this jsperf (感谢eaterofcode)。基于循环的实现在速度上与使用 Array.push.apply 但往往比 Array.slice.apply .

    有趣的是,如果要附加的数组是稀疏的,那么 forEach 基于上述方法可以充分利用其稀疏性,并优于 应用 基于方法;签出 this jsperf 如果你想自己测试这个。

    顺便说一下,别被诱惑了(就像我以前那样!)要进一步缩短foreach实现,请执行以下操作:

    Array.prototype.extend = function (array) {
        array.forEach(this.push, this);
    }
    

    因为这会产生垃圾结果!为什么?因为 Array.prototype.forEach 为它调用的函数提供三个参数-它们是:(element_value、element_index、source_array)。所有这些都将被推送到第一个数组中 前额 如果使用“foreach(this.push,this)”!

        4
  •  142
  •   odinho - Velmont    8 年前

    我觉得现在最优雅的是:

    arr1.push(...arr2);
    

    这个 MDN article on the spread operator 在ES2015(ES6)中提到这种甜蜜的方式:

    更好的推动

    示例:push通常用于将数组推送到现有数组的末尾 数组。在ES5中,通常这样做:

    var arr1 = [0, 1, 2];
    var arr2 = [3, 4, 5];
    // Append all items from arr2 onto arr1
    Array.prototype.push.apply(arr1, arr2);
    

    在扩展的ES6中,这变为:

    var arr1 = [0, 1, 2];
    var arr2 = [3, 4, 5];
    arr1.push(...arr2);
    

    请注意 arr2 不能太大(保持在100000项以下),因为调用堆栈溢出,根据jcdude的回答。

        5
  •  46
  •   Eric Robinson I_AM_PANDA    6 年前

    前几句关于 apply() 在javascript中帮助理解我们为什么要使用它:

    这个 应用程序() 方法使用给定的 this 价值,以及 作为数组提供的参数。

    推送A 列表 要添加到数组中的项。这个 应用程序() 但是,方法将函数调用的预期参数作为数组。这让我们很容易 push 将一个数组的元素与内置的 push() 方法。

    假设您有这些数组:

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

    只需这样做:

    Array.prototype.push.apply(a, b);
    

    结果将是:

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

    同样的事情也可以在ES6中使用spread操作符(“ ... “像这样:

    a.push(...b); //a = [1, 2, 3, 4, 5, 6, 7]; 
    

    更短更好,但目前所有浏览器都不完全支持。

    如果你想的话 移动 数组中的所有内容 b a 清空 在此过程中,您可以执行以下操作:

    while(b.length) {
      a.push(b.shift());
    } 
    

    结果如下:

    a = [1, 2, 3, 4, 5, 6, 7];
    b = [];
    
        6
  •  38
  •   Jules Colle    11 年前

    如果您想使用jquery,有 $.merge()

    例子:

    a = [1, 2];
    b = [3, 4, 5];
    $.merge(a,b);
    

    结果:A= [1, 2, 3, 4, 5]

        7
  •  18
  •   casillas    9 年前

    我喜欢 a.push.apply(a, b) 方法如上所述,如果需要,可以始终创建这样的库函数:

    Array.prototype.append = function(array)
    {
        this.push.apply(this, array)
    }
    

    像这样使用

    a = [1,2]
    b = [3,4]
    
    a.append(b)
    
        8
  •  13
  •   Peter Mortensen rohan kamat    6 年前

    可以使用 splice() :

    b.unshift(b.length)
    b.unshift(a.length)
    Array.prototype.splice.apply(a,b) 
    b.shift() // Restore b
    b.shift() // 
    

    但尽管它更丑,但它并不比 push.apply 至少在火狐3.0中没有。

        9
  •  4
  •   Peter Mortensen rohan kamat    6 年前

    此解决方案对我有效(使用ecmascript6的扩散运算符):

    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);
        10
  •  2
  •   Mr. Polywhirl    9 年前

    您可以创建一个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;
    }
        11
  •  1
  •   Peter Mortensen rohan kamat    6 年前

    我能看到非常好的答案,这取决于你的数组大小,你的要求和目标。它可以用不同的方式来完成。

    我建议使用javascript for循环:

    var a = [1, 2];
    var b = [3, 4, 5];
    
    for (i = 0; i < b.length; i++) {
        a.push(b[i]);
    }
    

    console.log(a) 输出将是

    Array [ 1, 2, 3, 4, 5 ]
    

    然后你就可以做你自己的功能了:

    function extendArray(a, b){
        for (i = 0; i < b.length; i++) {
            a.push(b[i]);
        }
        return a;
    }
    

    console.log(extendArray(a, b)); 输出将是

    数组[1,2,3,4,5]
    
        12
  •  0
  •   zCoder    11 年前

    组合答案…

    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
  •  0
  •   user3126309    8 年前

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

    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)
    

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

        14
  •  0
  •   Mahdi Pedram    5 年前

    使用 Array.extend 而不是 Array.push 对于超过150000条记录。

    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;
      };
    }
    
        15
  •  -1
  •   Peter Mortensen rohan kamat    6 年前

    答案非常简单。

    >>> 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.
    
        16
  •  -2
  •   elPastor    5 年前

    超级简单,不依赖于扩散运算符或应用,如果这是一个问题。

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

    在对此进行了一些性能测试之后,它的速度非常慢,但回答了有关不创建新数组的问题。concat速度明显更快,甚至jquery的 $.merge() 哎哟。

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