题 如何在特定索引处将项插入数组?


我正在寻找一个Javascript数组插入方法,风格为:

arr.insert(index, item)

最好是在jQuery中,但任何Javascript实现都会在这一点上完成。


2081
2018-02-25 14:29


起源


请注意,JQuery是一个DOM和事件操作库,而不是它自己的语言。它与数组操作无关。 - Jacque Goupil
api.jquery.com/jQuery.inArray 与DOM或事件无关。 jQuery已经演变成一个用于浏览器JS开发的混合工具包,导致人们期望它拥有一个适用于所有方法的方法。 - Tim
@Tim,但它仍然不是它自己的语言(仍然有一些问题,如“如何在jQuery中将两个数字相加”在这里SO) - Victor
@Victor不,永远不会。 jQuery很有用且相关,但它已经有了它的一天。 - Tim


答案:


你想要的是什么 splice 本机数组对象上的函数。

arr.splice(index, 0, item); 将插入 item 成 arr 在指定的索引处(删除 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());


3447
2018-02-25 14:32



谢谢,我以为我会觉得我觉得很愚蠢,但现在我知道答案我没有!为什么他们决定将一个更可搜索的术语用于同一个函数时称之为拼接?! - tags2k
@ tags2k:因为该函数不仅仅是插入项目而且它的名称已经在perl中建立了? - Christoph
DOC: developer.mozilla.org/en/JavaScript/Guide/... - Dingo
拼接 能够 插入,但同样频繁 才不是。例如: arr.splice(2,3) 将删除从索引2开始的3个元素。不传递第3个....第N个参数没有插入任何内容。所以这个名字 insert() 也不是正义。 - EBarr
我认为“拼接”一词是有道理的。拼接意味着加入或连接,也可以改变。您有一个已建立的数组,您现在正在“更改”,这将涉及添加或删除元素。您可以指定要在数组中启动的位置,然后指定要删除的旧项目数(如果有)以及最后添加的新元素列表。 Splice当然也是一个伟大的科幻术语。 - Jakub Keller


你可以实现 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' ]

208
2017-10-03 14:26



不要修改您不拥有的对象 - Pavlo
谁拥有阵列? Ecma脚本comitee?我的意思是如果你用Object.defineProperty做它可能没有Pavlo认为的那么糟糕。 - Capaj
要插入多个项目,您可以使用 Array.prototype.insert = function (index, items) { this.splice.apply(this, [index, 0].concat(items)); } - Ryan Smith
向数组添加内容的问题是,当你执行(i in arr){...}时,该函数将显示为元素 - rep_movsd
Pavlo所说的是 - 如果实现了本机插入方法,或者公司中的2个或更多开发人员会同样为数组对象创建插入,但实现会有所不同......嗯,你明白了。 - Adam Moszczyński


自定义数组 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"

DEMO:  http://jsfiddle.net/UPphH/


64
2018-03-25 17:45



是否有一种紧凑的方法让这个版本在参数中找到一个数组时合并一个数组? - Nolo
@Nolo是的,您可以在更新的答案中找到它。 - VisioN
我不明白第一个结果 ["b", "X", "Y", "Z", "c"]。为什么不呢 "d" 包括在内呢?在我看来,如果你把6作为第二个参数 slice() 并且从指定的索引开始,数组中有6个元素,那么你应该在返回值中获得所有6个元素。 (医生说 howMany 对于该参数。) developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... - Alexis Wilke
实际上,如果我使用3或更多的索引,我在输出中什么也得不到(案例1,FireFox) ["a", "b", "c", "d"].insert(2, "X", "Y", "Z").slice(3, 3); => [ ] - Alexis Wilke
@AlexisWilke在我使用的第一个例子中 slice 方法而不是 splice,你在评论中提到的。第二个参数 slice (命名 end)是 结束提取的从零开始的索引。 slice 提取但不包括 end。因此之后 insert 你有 ["a", "b", "X", "Y", "Z", "c", "d"], 从中 slice 提取索引来自的元素 1 取决于 6,即来自 "b" 至 "d" 但不包括在内 "d"。是否有意义? - VisioN


除了拼接之外,您可以使用这种方法,它不会改变原始数组,但会创建一个带有添加项的新数组。你应该尽可能避免变异。我在这里使用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]

这可以用来添加多个项目,通过稍微调整函数来使用其余运算符来处理新项目,并将其传播到返回的结果中

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]


54
2017-07-04 09:18



我正在寻找的答案。谢谢! - Alex Alexeev
这是一个好的,安全的方法吗?我问,因为这看起来如此优雅和简洁,但没有其他答案触及这一点。他们中的大多数修改原型对象! - Harsh Kanchina
@HarshKanchina这可能是因为大部分答案都是ES6之前的,但是根据我的经验,这种方法很常见 - Gaafar


如果要一次将多个元素插入到数组中,请查看此Stack Overflow答案: 在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);

33
2017-08-30 04:37



一旦创建了单元素arrayToInsert,insertAt()不会更好地调用insertArrayAt()吗?这避免了重复相同的代码。 - Matt Sach
这是何时使用'apply'的一个很好的例子 - CRice
我在这个方法中添加了一个removeCount参数,以利用splice在该索引中删除项目的能力:Array.prototype.splice.apply(array,[index,removeCount || 0] .concat(arrayToInsert)); - CRice


对于正确的函数编程和链接目的,发明 Array.prototype.insert() 是必不可少的。实际上,如果它已经返回变异数组而不是完全没有意义的空数组,那么splice可能是完美的。所以这就是它

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));


14
2018-05-13 23:22



“一个完全没有意义的空数组” - 它只在第二个参数为0时返回一个空数组。如果它大于0,则返回从数组中删除的项。鉴于您正在添加原型,并且 splice 改变原始数组,我不认为“适当的函数式编程”属于附近的任何地方 splice。 - cdbajorin
我们在这里讨论插入,Array.prototype.splice()的第二个参数必须为零。除了“我没有删除任何内容”之外,它返回的内容没有任何意义,因为我们使用它来插入项目,我们已经拥有了这些信息。如果您不想改变原始数组,那么您可以使用两个Array.prototype.slice()和一个Array.prototype.concat()操作执行相同的操作。随你便。 - Redu
你的第二个实现是整个页面中最干净的,你没有投票。请带走我的并保持良好的工作。 (你应该避免改变原型,但你已经知道了) - NiKo
我认为值得一提的是,其余参数是新ECMA 6号(developer.mozilla.org/en/docs/Web/JavaScript/Reference/... ) - Geza Turi


我推荐使用纯净的 JavaScript的 在这种情况下,JavaScript中也没有插入方法,但我们有一个方法 内置数组 为你做的工作的方法,它被称为 拼接...

让我们看看是什么 拼接()...

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

好的,想象我们下面有这个数组:

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

我们可以删除 3 喜欢这个:

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

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

[1, 2, 4, 5]

到目前为止,这么好,但我们如何使用splice向阵列添加新元素? 让我们回到3 ...

arr.splice(2, 0, 3);

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

我们用 拼接 再次,但这次是第二个论点,我们通过了 0,意味着我们想删除没有项目,但同时,我们添加第三个参数,即3将在第二个索引处添加...

你应该知道,我们可以 删除 和  同时,例如现在我们可以这样做:

arr.splice(2, 2, 3);

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

[1, 2, 3, 5];

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

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


7
2017-12-25 13:04





另一个可能的解决方案,使用 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);


5
2018-04-05 17:06





即使已经回答了这个问题,我还是将这个说明添加到另一种方法中。

我想放一个 已知数量 将项目分成数组,进入特定位置,因为它们来自“关联数组”(即一个对象),根据定义,它不能保证按排序顺序排列。我希望得到的数组是一个对象数组,但由于数组保证了它们的顺序,所以对象在数组中按特定的顺序排列。所以我这样做了。

首先是源对象,从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);

5
2017-12-04 18:36





我试过这个,工作正常!

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

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

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

2
2018-03-08 06:35



只需复制粘贴上面的答案。这不会给问题增加任何价值。要么你在现有的地方添加新的答案或评论。请尝试贡献新的东西。我们不想破坏这个社区 - hannad rehman


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

//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

1
2018-06-28 19:13