如何在特定索引(JavaScript)的数组中插入项目?


2930

我正在寻找一种JavaScript数组插入方法,其样式为:

arr.insert(index, item)

最好是在jQuery中,但此时任何JavaScript实现都可以。


95
请注意,JQuery是DOM和事件操作库,而不是它自己的语言。它与数组操作无关。
多米诺骨牌

25
api.jquery.com/jQuery.inArray与DOM或事件无关。jQuery已经发展成为用于浏览器JS开发的混合工具包,导致人们期望它具有适用于所有事物的方法。
蒂姆(Tim)

4
@Tim,但是它仍然不是自己的语言(SO上仍然有一些问题,例如“如何在jQuery中对两个数字求和”)
Victor

3
@Victor不,永远不会。jQuery有用且相关,但是它已经存在。
蒂姆(Tim)

1
另外,请参阅此文章,以获取令人惊讶的惊喜(:
noobie

Answers:


4751

您想要的是splice本机数组对象上的函数。

arr.splice(index, 0, item);将插入itemarr指定的索引处(0首先删除项目,即只是一个插入)。

在此示例中,我们将创建一个数组并将一个元素添加到索引2中:

var arr = [];
arr[0] = "Jani";
arr[1] = "Hege";
arr[2] = "Stale";
arr[3] = "Kai Jim";
arr[4] = "Borge";

console.log(arr.join());
arr.splice(2, 0, "Lene");
console.log(arr.join());


168
谢谢,我以为我问问会很愚蠢,但现在我知道了我不知道的答案!当在同一个函数中通常使用更易搜索的术语时,为什么他们到底决定将其称为拼接?!
标签2k

83
@ tags2k:因为该功能不只是插入项目,而且其名称已经在perl中建立?
Christoph


55
接头可以插入,但正如经常没有。例如: arr.splice(2,3)将从索引2开始删除3个元素。不传递第3个.... Nth参数,则不会插入任何内容。因此,这个名称insert()也无法做到这一点。
EBarr 2014年

14
我认为“拼接”一词很有意义。拼接意味着加入或连接,也意味着改变。您现在有一个“更改”的已建立数组,其中涉及添加或删除元素。您指定要在数组中的何处开始,然后指定要删除的旧项目数(如果有),最后指定要添加的新元素列表。当然,拼接也是一个很棒的科幻名词。
Jakub Keller 2014年

286

您可以通过执行以下Array.insert方法来实现该方法:

Array.prototype.insert = function ( index, item ) {
    this.splice( index, 0, item );
};

然后您可以像这样使用它:

var arr = [ 'A', 'B', 'D', 'E' ];
arr.insert(2, 'C');

// => arr == [ 'A', 'B', 'C', 'D', 'E' ]

9
要插入多个项目,你可以使用Array.prototype.insert = function (index, items) { this.splice.apply(this, [index, 0].concat(items)); }
莱恩史密斯

7
向数组添加内容的问题在于,当您执行for(i in arr){...}时,该函数将显示为元素
rep_movsd 2014年

7
但是请记住,不建议扩展本机类型,因为它可能会干扰其他代码或将来的功能。
marsze

16
不要修改您不拥有的对象
Luis Cabrera Benito

4
不要修改原型
satya164

141

除了拼接以外,您可以使用这种方法,该方法不会突变原始数组,但是会使用添加的项创建一个新数组。通常应尽可能避免突变。我在这里使用ES6传播算子。

const items = [1, 2, 3, 4, 5]

const insert = (arr, index, newItem) => [
  // part of the array before the specified index
  ...arr.slice(0, index),
  // inserted item
  newItem,
  // part of the array after the specified index
  ...arr.slice(index)
]

const result = insert(items, 1, 10)

console.log(result)
// [1, 10, 2, 3, 4, 5]

通过稍微调整函数以将rest运算符用于新项目,可以将其添加到多个项目中,并将其也分散到返回的结果中

const items = [1, 2, 3, 4, 5]

const insert = (arr, index, ...newItems) => [
  // part of the array before the specified index
  ...arr.slice(0, index),
  // inserted items
  ...newItems,
  // part of the array after the specified index
  ...arr.slice(index)
]

const result = insert(items, 1, 10, 20)

console.log(result)
// [1, 10, 20, 2, 3, 4, 5]


1
这是一种安全的好方法吗?我问,因为这看起来如此简洁明了,但没有其他答案。他们中的大多数都修改了原型对象!
严苛的中国(Kashchina)

5
@HarshKanchina这可能是因为大多数答案都在ES6之前,但是根据我的经验,这种方法现在非常普遍
gafi

77

自定义数组insert方法

1.具有多个参数和链接支持

/* Syntax:
   array.insert(index, value1, value2, ..., valueN) */

Array.prototype.insert = function(index) {
    this.splice.apply(this, [index, 0].concat(
        Array.prototype.slice.call(arguments, 1)));
    return this;
};

它可以插入多个元素(如本机splice一样)并支持链接:

["a", "b", "c", "d"].insert(2, "X", "Y", "Z").slice(1, 6);
// ["b", "X", "Y", "Z", "c"]

2.具有数组类型参数合并和链接支持

/* Syntax:
   array.insert(index, value1, value2, ..., valueN) */

Array.prototype.insert = function(index) {
    index = Math.min(index, this.length);
    arguments.length > 1
        && this.splice.apply(this, [index, 0].concat([].pop.call(arguments)))
        && this.insert.apply(this, arguments);
    return this;
};

它可以将参数中的数组与给定数组合并,还支持链接:

["a", "b", "c", "d"].insert(2, "V", ["W", "X", "Y"], "Z").join("-");
// "a-b-V-W-X-Y-Z-c-d"

演示: http : //jsfiddle.net/UPphH/


当它在参数中找到一个数组时,是否有一种紧凑的方法来使该版本合并数组?
2013年

我不明白第一个结果["b", "X", "Y", "Z", "c"]。为什么不"d"包括在内?在我看来,如果将6作为的第二个参数,slice()并且数组中从指定的索引开始有6个元素,那么应该在返回值中获得所有6个元素。(该医生说howMany该参数。)developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
亚历威尔克

实际上,如果我使用的索引为3或更大,则输出中没有任何内容(案例1,FireFox)["a", "b", "c", "d"].insert(2, "X", "Y", "Z").slice(3, 3);=>[ ]
Alexis Wilke 2014年

@AlexisWilke在第一个示例中,我使用slicemethod而不是splice,您在注释中引用了该方法。slice(名为end)的第二个参数是从零开始的索引,在该索引处终止提取。slice最多提取但不包括end。因此,在insert您拥有之后["a", "b", "X", "Y", "Z", "c", "d"],从中slice提取索引的元素,该索引从16,即从"b"到,"d"但不包括"d"。是否有意义?
2014年

41

如果您想一次将多个元素插入到数组中,请查看此堆栈溢出答案:将数组拼接成JavaScript中数组的更好方法

另外,这里有一些函数来说明这两个示例:

function insertAt(array, index) {
    var arrayToInsert = Array.prototype.splice.apply(arguments, [2]);
    return insertArrayAt(array, index, arrayToInsert);
}

function insertArrayAt(array, index, arrayToInsert) {
    Array.prototype.splice.apply(array, [index, 0].concat(arrayToInsert));
    return array;
}

最后是一个jsFiddle,因此您可以自己查看:http : //jsfiddle.net/luisperezphd/Wc8aS/

这就是您使用这些功能的方式:

// if you want to insert specific values whether constants or variables:
insertAt(arr, 1, "x", "y", "z");

// OR if you have an array:
var arrToInsert = ["x", "y", "z"];
insertArrayAt(arr, 1, arrToInsert);

1
一旦创建了单元素arrayToInsert,insertAt()会更好地调用insertArrayAt()吗?这样可以避免重复相同的代码。
Matt Sach 2012年

1
这是何时使用“应用”的一个很好的例子
CRice 2015年

我向此方法添加了removeCount参数,以利用剪接功能还可以删除该索引处的项:Array.prototype.splice.apply(array,[index,removeCount || 0] .concat(arrayToInsert));
CRice

23

为了适当的功能编程和链接目的,发明Array.prototype.insert()是必不可少的。如果拼接返回了变异数组而不是完全没有意义的空数组,则实际上拼接可能是完美的。所以就这样

Array.prototype.insert = function(i,...rest){
  this.splice(i,0,...rest)
  return this
}

var a = [3,4,8,9];
document.write("<pre>" + JSON.stringify(a.insert(2,5,6,7)) + "</pre>");

好吧,上面的代码Array.prototype.splice()修改了原来的数组,有些可能会抱怨,例如“您不应该修改不属于您的内容”,这也可能是正确的。因此,为了公共福利,我想提出一个Array.prototype.insert()不会改变原始数组的变量。它来了;

Array.prototype.insert = function(i,...rest){
  return this.slice(0,i).concat(rest,this.slice(i));
}

var a = [3,4,8,9],
    b = a.insert(2,5,6,7);
console.log(JSON.stringify(a));
console.log(JSON.stringify(b));


2
“完全没有意义的空数组”-仅当第二个参数为0时才返回空数组。如果它大于0,则返回从数组中删除的项目。鉴于您要添加一个原型并更改splice原始数组,所以我认为“适当的函数式编程”不属于附近的任何地方splice
chrisbajorin

我们在这里谈论插入,并且Array.prototype.splice()的第二个参数必须为零。它返回的内容除了“我还没有删除任何东西”之外没有其他意义,并且由于我们将其用于插入项目,因此我们已经具有该信息。如果您不想突变原始数组,则可以使用两个Array.prototype.slice()和一个Array.prototype.concat()操作进行相同的操作。由你决定。
Redu

1
您的第二个实现是整个页面中最干净的,并且您的投票为零。请带上我,保持良好的工作状态。(您应该避免改变原型,但您已经知道了)
NiKo 2016年

1
我认为值得一提的是其余参数是新的ECMA 6th(developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Geza Turi

18

我建议在这种情况下使用纯JavaScriptJavaScript中也没有insert方法,但是我们有一个方法,它是 内置的Array方法,可以为您完成工作,它称为splice ...。

让我们看看什么是splice() ...

splice()方法通过删除现有元素和/或添加新元素来更改数组的内容。

好吧,假设我们下面有这个数组:

const arr = [1, 2, 3, 4, 5];

我们可以这样删除3

arr.splice(arr.indexOf(3), 1);

它将返回3,但是如果现在检查arr,我们将:

[1, 2, 4, 5]

到目前为止,一切都很好,但是如何使用拼接将新元素添加到数组中呢?让我们把3放回去...

arr.splice(2, 0, 3);

让我们看看我们做了什么...

我们再次使用拼接,但是这次是第二个参数,我们传递0,这意味着我们不希望删除任何项目,但是与此同时,我们添加了第三个参数3,它将在第二个索引处添加。

您应该知道,我们可以同时删除添加,例如现在我们可以:

arr.splice(2, 2, 3);

这将删除索引2处的2个项目,然后在索引2处添加3,结果将是:

[1, 2, 3, 5];

这显示了拼接中的每个项目如何工作:

array.splice(start,deleteCount,item1,item2,item3 ...)


13

在特定索引处附加单个元素

//Append at specific position(here at index 1)
arrName.splice(1, 0,'newName1');
//1: index number, 0: number of element to remove, newName1: new element


//Append at specific position (here at index 3)
arrName[3] = 'newName1';

在特定索引处附加多个元素

//Append from index number 1
arrName.splice(1, 0,'newElemenet1', 'newElemenet2', 'newElemenet3');
//1: index number from where append start, 
//0: number of element to remove, 
//newElemenet1,2,3: new elements

8
值得注意的是arrName [3]没有追加,它会覆盖。
sfratini

它将元素添加到现有数组中,例如:arrName = ['xxx','yyy','zzz']; arrName.splice(1,0,'aaa','bbb','ccc'); 后打印arrName
Srikrushna

如果arrName具有3个以上的元素,则您将覆盖第3个元素,而不是附加元素。还是我看错了方向?
sfratini

如果我们在中间插入一个元素,它将移动下一个不覆盖的元素。请说明您的问题,您需要什么。拿一个数组(示例)以及您在输出中需要的内容。请评论我
Srikrushna

1
arrName[3] = 'newName1';如果数组只有3个元素,则@Srikrushna 将追加。如果索引3中有一个元素,它将被替换。如果您想附加在末尾,最好使用arrName.push('newName1');
敬畏

6

另一种可能的解决方案,使用Array#reduce

var arr = ["apple", "orange", "raspberry"],
    arr2 = [1, 2, 4];

function insert(arr, item, index) {
    arr = arr.reduce(function(s, a, i) {
      i == index ? s.push(item, a) : s.push(a);
      return s;
    }, []);   
    console.log(arr);
}

insert(arr, "banana", 1);
insert(arr2, 3, 2);


6

这有两种方法:

const array = [ 'My', 'name', 'Hamza' ];

array.splice(2, 0, 'is');

console.log("Method 1 : ", array.join(" "));

要么

Array.prototype.insert = function ( index, item ) {
    this.splice( index, 0, item );
};

const array = [ 'My', 'name', 'Hamza' ];
array.insert(2, 'is');

console.log("Method 2 : ", array.join(" "));


4

即使已经回答了这个问题,我仍在添加此注释,以供选择。

我想输入一个已知号码的项目放置到数组中的特定位置,因为它们来自“关联数组”(即对象),根据定义,这些数组不能保证按排序顺序排列。我希望结果数组是对象数组,但是对象要按数组中的特定顺序排列,因为数组可以保证它们的顺序。所以我做到了。

首先是源对象,即从PostgreSQL检索的JSONB字符串。我想按每个子对象中的“ order”属性对其进行排序。

var jsonb_str = '{"one": {"abbr": "", "order": 3}, "two": {"abbr": "", "order": 4}, "three": {"abbr": "", "order": 5}, "initialize": {"abbr": "init", "order": 1}, "start": {"abbr": "", "order": 2}}';

var jsonb_obj = JSON.parse(jsonb_str);

由于对象中的节点数是已知的,因此我首先创建一个具有指定长度的数组:

var obj_length = Object.keys(jsonb_obj).length;
var sorted_array = new Array(obj_length);

然后迭代对象,将新创建的临时对象放置到数组中的所需位置,而不会发生任何真正的“排序”。

for (var key of Object.keys(jsonb_obj)) {
  var tobj = {};
  tobj[key] = jsonb_obj[key].abbr;

  var position = jsonb_obj[key].order - 1;
  sorted_array[position] = tobj;
}

console.dir(sorted_array);

3

任何仍然对此有疑问并尝试过上述所有选项却从未获得过它的人。我正在分享我的解决方案,这是为了考虑到您不会明确声明对象与数组的属性。

function isIdentical(left, right){
    return JSON.stringify(left) === JSON.stringify(right);
}

function contains(array, obj){
    let count = 0;
    array.map((cur) => {
          if(this.isIdentical(cur, obj)) count++;
    });
    return count > 0;
}

这是对引用数组进行迭代并将其与您要检查的对象进行比较的组合,将它们都转换为字符串,然后在匹配时进行迭代。然后,您可以数数。这可以改善,但这是我解决的地方。希望这可以帮助。


3

采取减少收益的方法如下:

function insert(arr, val, index) {
    return index >= arr.length 
        ? arr.concat(val)
        : arr.reduce((prev, x, i) => prev.concat(i === index ? [val, x] : x), []);
}

因此,以这种方式,我们可以返回在索引处插入元素的新数组(这将是一种很酷的功能方式-比使用push或splice更好),并且如果索引大于数组的长度,则将其插入在最后。


3

Array#splice()是要走的路,除非您真的想避免对数组进行变异。鉴于2个阵列arr1arr2,这里是你会怎么插入的内容arr2arr1第一个元素后:

const arr1 = ['a', 'd', 'e'];
const arr2 = ['b', 'c'];

arr1.splice(1, 0, ...arr2); // arr1 now contains ['a', 'b', 'c', 'd', 'e']

console.log(arr1)

如果您担心变异的阵列(例如,如果使用Immutable.js),您可以改用slice(),不要与混淆splice()'p'

const arr3 = [...arr1.slice(0, 1), ...arr2, ...arr1.slice(1)];

2

我试过了,它工作正常!

var initialArr = ["India","China","Japan","USA"];
initialArr.splice(index, 0, item);

索引是您要插入或删除元素的位置。0,即第二个参数定义要删除的索引中元素的数量。item是要在数组中创建的新条目。可以是一个或多个。

initialArr.splice(2, 0, "Nigeria");
initialArr.splice(2, 0, "Australia","UK");

4
只需复制粘贴上面的答案即可。这不会给问题增加任何价值。您可以添加新答案或对现有答案发表评论。请尝试贡献新的东西。我们不想破坏这个社区
Hannad Rehman

1

这是我在一个应用程序中使用的工作功能。

这检查项目是否退出

let ifExist = (item, strings = [ '' ], position = 0) => {
     // output into an array with empty string. Important just in case their is no item. 
    let output = [ '' ];
    // check to see if the item that will be positioned exist.
    if (item) {
        // output should equal to array of strings. 
        output = strings;
       // use splice in order to break the array. 
       // use positition param to state where to put the item
       // and 0 is to not replace an index. Item is the actual item we are placing at the prescribed position. 
        output.splice(position, 0, item);
    }
    //empty string is so we do not concatenate with comma or anything else. 
    return output.join("");
};

然后我在下面称呼它。

ifExist("friends", [ ' ( ', ' )' ], 1)}  // output: ( friends )
ifExist("friends", [ ' - '], 1)}  // output:  - friends 
ifExist("friends", [ ':'], 0)}  // output:   friends: 

1

线程有点旧,但是我必须同意上面的Redu,因为拼接肯定有一些令人困惑的接口。cdbajorin给出的响应是:“仅当第二个参数为0时,它才返回一个空数组。如果它大于0,则它返回从数组中删除的项目”,这是正确的。该函数的目的是进行拼接,或者如Jakob Keller先前所述,“进行连接或连接,也进行更改。您现在要更改的已建立数组将涉及添加或删除元素……。”鉴于此,返回的元素的值(如果有的话)充其量是尴尬的。我100%同意,如果此方法返回了看起来很自然的结果,那么它可能会更适合于链接,这是一个添加了拼接元素的新数组。然后,您可以对返回的数组执行[[19“,” 17“]。splice(1,0,” 18“)。join(” ...“)之类的操作。它返回已删除内容的事实只是个废话恕我直言。如果该方法的目的是“切出一组元素”,那仅仅是目的。似乎,如果我不知道要切出的内容,可能没有什么理由要切掉那些元素,不是吗?如果它的行为像concat,map,reduce,slice等,那将是更好的做法,其中从现有数组中创建一个新数组,而不是对现有数组进行突变。这些都是可链接的,这是一个重要的问题。链数组操作相当普遍。似乎该语言需要朝着另一个方向发展,并尽可能地坚持下去。Javascript具有功能性且声明性较差,这似乎是对规范的奇怪偏离。


-2

性能

今天(2020.04.24),我将对大型和小型阵列的选定解决方案进行测试。我在MacOs High Sierra 10.13.6,Chrome 81.0,Safari 13.1,Firefox 75.0上进行了测试。

结论

对于所有浏览器

  • 令人惊讶的是,对于小型阵列,基于slicereduce(D,E,F)的非就地解决方案通常比就地解决方案快10到100倍
  • 对于大型阵列,基于splice(AI,BI,CI)的就地解决方案最快(有时约100倍-但取决于阵列大小)
  • 小型阵列的BI解决方案最慢
  • 对于大型阵列,E解决方案最慢

在此处输入图片说明

细节

测试分为两组:就地解决方案(AI,BI,CI)和非就地解决方案(D,E,F),并且针对两种情况进行了测试

  • 测试包含10个元素的数组-您可以在此处运行
  • 测试具有1.000.000元素的数组-您可以在此处运行

经测试的代码显示在下面的代码片段中

铬上小阵列的示例结果如下

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.