我正在寻找一种 JavaScript 数组插入方法,其样式为:
arr.insert(index, item)
最好在 jQuery 中,但此时任何 JavaScript 实现都可以。
您希望在原生数组对象上使用 splice
函数。
arr.splice(index, 0, item);
将在指定的 index
处将 item
插入到 arr
中(首先删除 0
项,即它只是一个插入)。
在此示例中,我们将创建一个数组并将一个元素添加到索引 2 中:
var arr = []; arr[0] = "贾尼"; arr[1] = "黑格"; arr[2] = "陈旧"; arr[3] = "凯吉姆"; arr[4] = "博尔赫";控制台.log(arr.join()); // Jani,Hege,Stale,Kai Jim,Borge arr.splice(2, 0, "Lene");控制台.log(arr.join()); // Jani,Hege,Lene,Stale,Kai Jim,Borge
您可以通过执行以下操作来实现 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' ]
Array.prototype.insert = function (index, items) { this.splice.apply(this, [index, 0].concat(items)); }
除了拼接之外,您可以使用这种不会改变原始数组的方法,但它会创建一个包含添加项的新数组。当您需要避免突变时,它很有用。我在这里使用 ES6 扩展运算符。
const items = [1, 2, 3, 4, 5] const insert = (arr, index, newItem) => [ // 指定索引之前的部分数组 ...arr.slice(0, index),/ / 插入项 newItem, // 指定索引之后的数组部分 ...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) => [ // 指定索引之前的部分数组 ...arr.slice(0, index ), // 插入的项目 ...newItems, // 指定索引之后的数组部分 ...arr.slice(index) ] const result = insert(items, 1, 10, 20) console.log(result) // [1, 10, 20, 2, 3, 4, 5]
splice()
之前调用 slice()
。永远不要将 ES6 用于如此琐碎的事情,这些事情可以用其他 API 做得更好、更干净。
slice()
将分配一个新数组,实际上,splice()
也会分配一个新数组,因为它返回一个包含已删除项目的数组(在这种情况下为空数组)。在这些情况下运行基准测试表明拼接更快(约 30%),但我们处于每秒数百万次操作的范围内,因此除非您的应用程序正在执行 大量 此类操作在一个紧密的循环中,它不会有任何区别。
自定义数组插入方法
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/
["b", "X", "Y", "Z", "c"]
。为什么不包括 "d"
?在我看来,如果您将 6 作为 slice()
的第二个参数,并且数组中有 6 个元素从指定的索引开始,那么您应该在返回值中获得所有 6 个元素。 (文档说该参数为 howMany
。)developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
["a", "b", "c", "d"].insert(2, "X", "Y", "Z").slice(3, 3);
=> [ ]
slice
方法,而不是您在评论中提到的 splice
。 slice
的第二个参数(名为 end
)是 结束提取的从零开始的索引。 slice
提取最多但不包括 end
。因此,在 insert
之后有 ["a", "b", "X", "Y", "Z", "c", "d"]
,slice
从中提取索引从 1
到 6
的元素,即从 "b"
到 "d"
但不包括 "d"
。是否有意义?
如果您想一次将多个元素插入到数组中,请查看此 Stack Overflow 答案:A better way to splice an array into an array in 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);
对于正确的函数式编程和链接目的,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("
" + JSON.stringify(a.insert(2,5,6,7)) + "");
好吧,上面的 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));
splice
改变了原始数组,我认为“正确的函数式编程”不属于 splice
附近的任何地方。
解决方案与性能
今天(2020.04.24)我为大小阵列选择的解决方案进行测试。我在 Chrome 81.0、Safari 13.1 和 Firefox 75.0 上的 macOS v10.13.6 (High Sierra) 上对它们进行了测试。
结论
适用于所有浏览器
令人惊讶的是,对于小型阵列,基于 slice 和 reduce (D,E,F) 的非就地解决方案通常比就地解决方案快 10 倍至 100 倍
对于大型阵列,基于拼接(AI、BI 和 CI)的就地解决方案最快(有时约为 100 倍 - 但取决于阵列大小)
对于小型阵列,BI 解决方案最慢
对于大阵列,E 解决方案最慢
https://i.stack.imgur.com/gZjhH.png
细节
测试分为两组:就地解决方案(AI、BI 和 CI)和非就地解决方案(D、E 和 F),并针对两种情况进行:
测试一个有 10 个元素的数组 - 你可以在这里运行它
测试一个包含 1,000,000 个元素的数组 - 你可以在这里运行它
测试代码显示在以下代码段中:
函数 AI(arr, i, el) { arr.splice(i, 0, el);返回 arr; } 函数 BI(arr, i, el) { Array.prototype.splice.apply(arr, [i, 0, el]);返回 arr; } 函数 CI(arr, i, el) { Array.prototype.splice.call(arr, i, 0, el);返回 arr; } 函数 D(arr, i, el) { return arr.slice(0, i).concat(el, arr.slice(i)); } 函数 E(arr, i, el) { 返回 [...arr.slice(0, i), el, ...arr.slice(i)] } 函数 F(arr, i, el) { 返回 arr .reduce((s, a, j)=> (ji ? s.push(a) : s.push(el, a), s), []); } // ------------- // 测试 // ------------- 让 arr = ["a", "b", "c", “d”、“e”、“f”];让 log = (n, f) => { 让 a = f([...arr], 3, "NEW"); console.log(`${n}: [${a}]`); };日志(“人工智能”,人工智能);日志('BI',BI);日志('CI',CI);日志('D',D);日志('E',E);日志('F',F);此代码段仅显示经过测试的代码(它不执行测试)
Google Chrome 上的小数组的示例结果如下:
https://i.stack.imgur.com/cS1YZ.png
使用 Array.prototype.splice()
是实现它的简单方法
const numbers = ['one', 'two', 'four', 'five'] numbers.splice(2, 0, 'three');控制台日志(数字)
详细了解 Array.prototype.splice()
here
在这种情况下,我建议使用纯 JavaScript。 JavaScript 中也没有任何插入方法,但我们有一个方法是内置的 Array 方法,它可以为您完成这项工作。这叫拼接...
让我们看看什么是 splice()...
splice() 方法通过删除现有元素和/或添加新元素来更改数组的内容。
好的,假设我们在下面有这个数组:
const arr = [1, 2, 3, 4, 5];
我们可以像这样删除 3
:
arr.splice(arr.indexOf(3), 1);
它将返回 3,但如果我们现在检查 arr,我们有:
[1, 2, 4, 5]
到目前为止,一切都很好,但是我们如何使用拼接将新元素添加到数组中?
让我们把3放回arr中......
arr.splice(2, 0, 3);
让我们看看我们做了什么...
我们再次使用 splice,但是这次对于第二个参数,我们传递了 0,这意味着我们不想删除任何项目,但同时,我们添加了第三个参数,即将添加到第二个索引处的 3 ...
您应该知道我们可以同时删除和添加。例如,现在我们可以这样做:
arr.splice(2, 2, 3);
这将删除索引 2 处的两个项目。然后在索引 2 处添加 3,结果将是:
[1, 2, 3, 5];
这显示了拼接中的每个项目是如何工作的:
array.splice(开始, deleteCount, item1, item2, item3 ...)
这里有两种方法:
常量数组 = ['我的','名字','Hamza']; array.splice(2, 0, '是'); console.log("方法一:", array.join(" "));
或者
Array.prototype.insert = function (index, item) { this.splice(index, 0, item); };常量数组 = ['我的','名字','Hamza']; array.insert(2, '是'); console.log("方法二:", array.join(""));
在特定索引处附加单个元素
// Append at a 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 a 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
arrName[3] = 'newName1';
将追加。如果索引 3 中有一个元素,它将被替换。如果要在末尾追加,最好使用 arrName.push('newName1');
Array#splice()
是要走的路,除非你真的想避免改变数组。给定 2 个数组 arr1
和 arr2
,以下是如何将 arr2
的内容插入到 arr1
中的第一个元素之后:
常量 arr1 = ['a', 'd', 'e'];常量 arr2 = ['b', 'c']; arr1.splice(1, 0, ...arr2); // arr1 现在包含 ['a', 'b', 'c', 'd', 'e'] console.log(arr1)
如果您担心改变数组(例如,如果使用 Immutable.js),您可以改用 slice()
,不要将 splice()
与 'p'
混淆。
const arr3 = [...arr1.slice(0, 1), ...arr2, ...arr1.slice(1)];
另一种可能的解决方案,使用 Array.reduce
。
const arr = [“苹果”,“橙色”,“覆盆子”];常量 arr2 = [1, 2, 4]; const insert = (arr, item, index) => arr.reduce(function(s, a, i) { i === index ? s.push(item, a) : s.push(a); return s; }, []);控制台.log(插入(arr,“香蕉”,1)); console.log(插入(arr2, 3, 2))
您可以为此使用 splice()
添加元素时,splice()
方法通常接收三个参数:
要添加项目的数组的索引。要删除的项目数,在本例中为 0。要添加的元素。
let array = ['item 1', 'item 2', 'item 3'] let insertAtIndex = 0 let itemsToRemove = 0 array.splice(insertAtIndex, itemsToRemove, '在索引 0 上插入这个字符串') console.log(array)
即使已经回答了这个问题,我还是添加了这个注释作为替代方法。
我想将已知数量的项目放入一个数组中的特定位置,因为它们来自一个“关联数组”(即一个对象),根据定义,它不能保证按排序顺序。我希望得到的数组是一个对象数组,但对象在数组中的顺序是特定的,因为数组保证了它们的顺序。所以我做了这个。
首先是源对象,从 PostgreSQL 检索的 JSONB 字符串。我想让它按每个子对象中的“顺序”属性排序。
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);
不可变插入
如果您需要就地插入数组,使用 splice
方法无疑是最佳答案。
但是,如果您正在寻找一个不可变函数,它返回一个新的更新数组,而不是在插入时改变原始数组,您可以使用以下函数。
函数插入(数组,索引){ 常量项 = Array.prototype.slice.call(参数,2); return [].concat(array.slice(0, index), items, array.slice(index)); } 常量列表 = ['一', '二', '三']; const list1 = insert(list, 0, '零'); // 插入单个项目 const list2 = insert(list, 3, 'four', 'five', 'six'); // 插入多个 console.log('原始列表:', list); console.log('插入的 list1: ', list1); console.log('插入的 list2: ', list2);
注意:这是一种预ES6方式,因此它适用于旧版和新版浏览器。
如果您使用的是 ES6,那么您也可以试试 rest parameters;见this answer。
任何对此仍有疑问并尝试过先前答案中的所有选项但从未得到过的人。我正在分享我的解决方案,这是考虑到您不想明确声明对象与数组的属性。
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;
}
这是迭代引用数组并将其与您要检查的对象进行比较,将它们都转换为字符串,然后在匹配时进行迭代的组合。然后你就可以数数了。这可以改进,但这是我解决的地方。
取reduce方法的利润如下:
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 更好),其中元素插入到索引处,如果索引大于数组的长度,它将被插入在最后。
我试过了,它工作正常!
var initialArr = ["India","China","Japan","USA"];
initialArr.splice(index, 0, item);
索引是您要插入或删除元素的位置。
0,即第二个参数,定义要从索引中移除的元素个数。 item
包含您要在数组中创建的新条目。它可以是一个或多个。
initialArr.splice(2, 0, "Nigeria");
initialArr.splice(2, 0, "Australia","UK");
这是我在我的一个应用程序中使用的一个工作函数。
这将检查项目是否存在:
let ifExist = (item, strings = [ '' ], position = 0) => {
// Output into an array with an empty string. Important just in case their isn't any item.
let output = [ '' ];
// Check to see if the item that will be positioned exist.
if (item) {
// Output should be equal to an array of strings.
output = strings;
// Use splice() in order to break the array.
// Use positional parameters 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:
我不得不同意 Redu 的回答,因为 splice() 肯定有一些令人困惑的界面。 cdbajorin 给出的响应“它只在第二个参数为 0 时返回一个空数组。如果它大于 0,它返回从数组中删除的项目”,虽然准确,但证明了这一点。
该功能的目的是拼接,或者如 Jakob Keller 之前所说,“加入或连接,也可以改变。
您现在正在更改一个已建立的数组,这将涉及添加或删除元素......”鉴于此,被删除的元素(如果有的话)的返回值充其量是尴尬的。我 100% 同意这一点方法可能更适合链接,如果它返回了看起来很自然的东西,一个添加了拼接元素的新数组。然后你可以做类似 ["19", "17"].splice(1,0,"18" ).join("...") 或任何你喜欢的返回数组。
它返回已删除的内容的事实只是恕我直言。如果该方法的目的是“切出一组元素”并且这是它的唯一意图,也许。似乎如果我不知道我已经剪掉了什么,我可能没有理由剪掉这些元素,不是吗?
如果它的行为类似于 concat()、map()、reduce()、slice() 等,其中一个新数组是由现有数组创建的,而不是对现有数组进行变异,那会更好。这些都是可链接的,这是一个重要问题。链式数组操作相当普遍。
似乎语言需要朝着一个或另一个方向发展,并尽可能地坚持下去。 JavaScript 是函数式的且声明性较少,这似乎是对规范的奇怪偏离。
我喜欢一点安全,我用这个:
Array.prototype.Insert = function (item, before) { if (!item) return; if (before == null || before < 0 || before > this.length - 1) { this.push(item);返回; } this.splice(之前,0,项目); } var t = ["a", "b"] t.Insert("v", 1) console.log(t)
这是现代(Typescript 功能)方式:
export const insertItemInList = <T>(
arr: T[],
index: number,
newItem: T
): T[] => [...arr.slice(0, index), newItem, ...arr.slice(index)]
我这样做:
const insert = (what, where, index) =>
([...where.slice(0, index), what , ...where.slice(index, where.length)]);
const insert = (what, where, index) => ([...where.slice(0, index), what , ...where.slice(index, where.length)]);常量列表 = [1, 2, 3, 4, 5, 6]; const newList = insert('a', list, 2); console.log(newList.indexOf('a') === 2);
这是一个支持同时插入多个值的简单函数:
function add_items_to_array_at_position(array, index, new_items)
{
return [...array.slice(0, index), ...new_items, ...array.slice(index)];
}
使用示例:
let old_array = [1,2,5];
let new_array = add_items_to_array_at_position(old_array, 2, [3,4]);
console.log(new_array);
//Output: [1,2,3,4,5]
arr.splice(2,3)
将删除从索引 2 开始的 3 个元素。如果不传递第 3 个....第 N 个参数,则不会插入任何内容。所以名称insert()
也不公平。