使用 JavaScript 从数组中删除对象
Posted
技术标签:
【中文标题】使用 JavaScript 从数组中删除对象【英文标题】:Remove Object from Array using JavaScript 【发布时间】:2012-04-18 23:20:24 【问题描述】:如何从数组中删除对象?
我希望从someArray
中删除包含名称Kristian
的对象。例如:
someArray = [name:"Kristian", lines:"2,5,10",
name:"John", lines:"1,19,26,96"];
我想实现:
someArray = [name:"John", lines:"1,19,26,96"];
【问题讨论】:
【参考方案1】:对数组使用拼接函数。指定开始元素的位置和要删除的子序列的长度。
someArray.splice(pos, 1);
【讨论】:
【参考方案2】:您可以使用多种方法从数组中删除项目:
//1
someArray.shift(); // first element removed
//2
someArray = someArray.slice(1); // first element removed
//3
someArray.splice(0, 1); // first element removed
//4
someArray.pop(); // last element removed
//5
someArray = someArray.slice(0, someArray.length - 1); // last element removed
//6
someArray.length = someArray.length - 1; // last element removed
如果要删除位置x
的元素,请使用:
someArray.splice(x, 1);
或者
someArray = someArray.slice(0, x).concat(someArray.slice(-x));
回复@chill182的评论:可以使用Array.filter
,或Array.splice
结合Array.findIndex
(见MDN)从数组中删除一个或多个元素,例如
// non destructive filter > noJohn = John removed, but someArray will not change
let someArray = getArray();
let noJohn = someArray.filter( el => el.name !== "John" );
log(`let noJohn = someArray.filter( el => el.name !== "John")`,
`non destructive filter [noJohn] =`, format(noJohn));
log(`**someArray.length $someArray.length`);
// destructive filter/reassign John removed > someArray2 =
let someArray2 = getArray();
someArray2 = someArray2.filter( el => el.name !== "John" );
log("",
`someArray2 = someArray2.filter( el => el.name !== "John" )`,
`destructive filter/reassign John removed [someArray2] =`,
format(someArray2));
log(`**someArray2.length after filter $someArray2.length`);
// destructive splice /w findIndex Brian remains > someArray3 =
let someArray3 = getArray();
someArray3.splice(someArray3.findIndex(v => v.name === "Kristian"), 1);
someArray3.splice(someArray3.findIndex(v => v.name === "John"), 1);
log("",
`someArray3.splice(someArray3.findIndex(v => v.name === "Kristian"), 1),`,
`destructive splice /w findIndex Brian remains [someArray3] =`,
format(someArray3));
log(`**someArray3.length after splice $someArray3.length`);
// if you're not sure about the contents of your array,
// you should check the results of findIndex first
let someArray4 = getArray();
const indx = someArray4.findIndex(v => v.name === "Michael");
someArray4.splice(indx, indx >= 0 ? 1 : 0);
log("", `someArray4.splice(indx, indx >= 0 ? 1 : 0)`,
`check findIndex result first [someArray4] = (nothing is removed)`,
format(someArray4));
log(`**someArray4.length (should still be 3) $someArray4.length`);
// -- helpers --
function format(obj)
return JSON.stringify(obj, null, " ");
function log(...txt)
document.querySelector("pre").textContent += `$txt.join("\n")\n`
function getArray()
return [ name: "Kristian", lines: "2,5,10",
name: "John", lines: "1,19,26,96",
name: "Brian", lines: "3,9,62,36" ];
<pre>
**Results**
</pre>
【讨论】:
@Klemzy 你不是指索引吗?按价值...? 原始问题询问如何从数组中删除名称为“Kristian”的对象。您的答案假设它是数组中的第一项,但如果 Kristin 不在第一项中怎么办?那你的答案就不行了。 @chill182:这不是一个具体的答案,而是一个更普遍的答案。从中,您应该能够推断出删除元素的方法。 如果你想删除位置 x 处的元素 ...可能是删除第一个元素以外的其他元素的提示,对吧? 拼接函数对我很有帮助,但你不应该重新分配 someArray。这将导致 someArray 包含已删除的项目,而不是包含已删除项目的结果数组。 在splice
中使用之前,您应该检查findIndex
结果。如果数组中没有匹配条件的元素findIndex
将返回-1
,并将其直接放入splice
将导致数组中最后一个元素的任意删除。【参考方案3】:
干净的解决方案是使用Array.filter
:
var filtered = someArray.filter(function(el) return el.Name != "Kristian"; );
问题在于它在 IE does not work。但是,您可以包含来自 javascript 库(例如 underscore.js)的代码,该库为任何浏览器实现此功能。
【讨论】:
这将删除所有找到的匹配项,而不仅仅是第一个 并且它会返回一个新的数组而不是修改原来的数组。根据用例,这可能是也可能不是您想要的。 @JochieNabuurs 它确实是一个新数组。但是,对象保持不变。您仍然可以修改每个对象的值,它将反映在原始数组的对象上。 至于这会返回一个新数组,只需将解决方案更改为someArray = someArray.filter(function(el) return el.Name != "Kristian"; );
地址,不是吗?
毫无疑问,它会起作用。但是,如果您关心内存管理,它无论如何都会创建一个新对象。我不想让我挑剔,这对任何情况都有效。但是,如果出于任何原因您正在处理一个非常大的数组,您应该使用相同的对象处理删除元素。【参考方案4】:
最简单的解决方案是创建一个按名称存储每个对象的索引的映射,如下所示:
//adding to array
var newPerson = name:"Kristian", lines:"2,5,10"
someMap[ newPerson.name ] = someArray.length;
someArray.push( newPerson );
//deleting from the array
var index = someMap[ 'Kristian' ];
someArray.splice( index, 1 );
【讨论】:
我喜欢这个想法,但也必须问,这样的想法在添加索引时的内存使用限制是多少?我有一个数组,我想在对象中的 2 个不同字段上建立索引,所以除了原始源数组之外,我还有 2 个映射。这是为查找速度付出的小代价,还是有更高效的内存解决方案?【参考方案5】:如图所示,您的“数组”是无效的 JavaScript 语法。花括号 用于具有属性名称/值对的对象,而方括号
[]
用于数组 - 如下所示:
someArray = [name:"Kristian", lines:"2,5,10", name:"John", lines:"1,19,26,96"];
在这种情况下,您可以使用.splice()
method 删除项目。要删除第一项(索引 0),请说:
someArray.splice(0,1);
// someArray = [name:"John", lines:"1,19,26,96"];
如果您不知道索引但想在数组中搜索以找到名称为“Kristian”的项目以删除您可以这样做:
for (var i =0; i < someArray.length; i++)
if (someArray[i].name === "Kristian")
someArray.splice(i,1);
break;
编辑:我刚刚注意到你的问题被标记为“jQuery”,所以你可以试试$.grep()
method:
someArray = $.grep(someArray,
function(o,i) return o.name === "Kristian"; ,
true);
【讨论】:
他们为什么要添加重载?当然你可以放 != "Kristian"。重载的目的是什么? @markthewizard1234 - 你的意思是$.grep()
中的“反转”布尔参数吗?在这个例子中它并没有增加太多,是的,我可以放!=
,但在其他情况下,你可能已经定义了一个函数,恰好对你想要的 grep 进行相反的测试,所以不如除了定义一个额外的函数,你可以使用这个重载来反转结果。
啊,所以如果你有一个包含 grep 的包装函数,你可以将布尔值设置为参数。明白了,谢谢!
@markthewizard1234 - 你可以,但这不是我的想法:想象你有function isEven(num) return num%2===0
。您可以使用 $.grep(someArray, isEven)
从数组中获取偶数,或者使用 $.grep(someArray, isEven, true)
执行相反操作并获取非偶数。【参考方案6】:
您的数组语法似乎有错误,因此假设您指的是数组而不是对象,Array.splice 是您的朋友:
someArray = [name:"Kristian", lines:"2,5,10", name:"John", lines:"1,19,26,96"];
someArray.splice(1,1)
【讨论】:
【参考方案7】:我建议使用 lodash.js 或 sugar.js 来完成以下常见任务:
// lodash.js
someArray = _.reject(someArray, function(el) return el.Name === "Kristian"; );
// sugar.js
someArray.remove(function(el) return el.Name === "Kristian"; );
在大多数项目中,拥有一组由此类库提供的辅助方法非常有用。
【讨论】:
我认为下划线的例子有点不对劲。应该是someArray = _.reject(someArray, function(el) return el.Name === "Kristian"; );
如果不想使用underscore.js或sugar.js,可以这样做someArray = someArray.filter(function(e) return e.Name !== "Kristian"; );
我想要的另一件事,数组中的每个对象都有单独的按钮。如果我想在单击的数组按钮中删除该特定对象。怎么做 。我已经使用 Angular js ng-repeat 来生成项目。你能帮帮我吗
这里要逆天了;建议一个包含整个库的简单目的是从对象中删除项目(js干净地支持开箱即用,如接受的答案所示)是糟糕的形式。它给你的代码增加了不必要的重量和复杂性,除非你已经需要它来实现库提供的更强大的功能。
为了简单的操作,我绝不建议包含库【参考方案8】:
虽然这可能不适合这种情况,但前几天我发现,如果您不需要更改数组的大小,也可以使用 delete
关键字从数组中删除一个项目,例如
var myArray = [1,2,3];
delete myArray[1];
console.log(myArray[1]); //undefined
console.log(myArray.length); //3 - doesn't actually shrink the array down
【讨论】:
【参考方案9】:使用 javascript 的 splice() 函数。
这可能会有所帮助:http://www.w3schools.com/jsref/jsref_splice.asp
【讨论】:
【参考方案10】:这个怎么样?
$.each(someArray, function(i)
if(someArray[i].name === 'Kristian')
someArray.splice(i,1);
return false;
);
【讨论】:
这不会导致错误,因为$.each()
在循环之前缓存了数组长度,因此如果您删除元素$.each()
将运行超过(现在更短)数组的末尾。 (那么someArray[i]
将变为undefined
并且undefined.name
将崩溃。)
然后在拼接后加一个'return false'。
这不是javascript。 -1
请注意这个答案需要jQuery【参考方案11】:
投票给UndercoreJS 以简单地处理数组。
_.without() 函数有助于删除元素:
_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
=> [2, 3, 4]
【讨论】:
最佳解决方案。适用于对象数组。【参考方案12】:我制作了一个动态函数,获取对象数组、键和值,并在删除所需对象后返回相同的数组:
function removeFunction (myObjects,prop,valu)
return myObjects.filter(function (val)
return val[prop] !== valu;
);
完整示例:DEMO
var obj =
"results": [
"id": "460",
"name": "Widget 1",
"loc": "Shed"
,
"id": "461",
"name": "Widget 2",
"loc": "Kitchen"
,
"id": "462",
"name": "Widget 3",
"loc": "bath"
]
;
function removeFunction (myObjects,prop,valu)
return myObjects.filter(function (val)
return val[prop] !== valu;
);
console.log(removeFunction(obj.results,"id","460"));
【讨论】:
【参考方案13】:someArray = jQuery.grep(someArray , function (value)
return value.name != 'Kristian';
);
【讨论】:
【参考方案14】:这是一个适合我的功能:
function removeFromArray(array, value)
var idx = array.indexOf(value);
if (idx !== -1)
array.splice(idx, 1);
return array;
【讨论】:
我想要的另一件事,数组中的每个对象都有单独的按钮。如果我想在单击的数组按钮中删除该特定对象。怎么做 。我已经使用 Angular js ng-repeat 来生成项目。你能帮帮我吗【参考方案15】:splice(i, 1) 其中 i 是数组的增量索引,将删除对象。 但请记住 splice 也会重置数组长度,因此请注意“未定义”。使用您的示例,如果您删除“Kristian”,那么在循环内的下一次执行中,i 将为 2,但 someArray 的长度为 1,因此如果您尝试删除“John”,您将收到“未定义”错误.一个解决方案虽然不优雅,但有一个单独的计数器来跟踪要删除的元素的索引。
【讨论】:
【参考方案16】:你可以使用 array.filter()。
例如
someArray = [name:"Kristian", lines:"2,5,10",
name:"John", lines:"1,19,26,96"];
someArray = someArray.filter(function(returnableObjects)
return returnableObjects.name !== 'Kristian';
);
//someArray will now be = [name:"John", lines:"1,19,26,96"];
箭头函数:
someArray = someArray.filter(x => x.name !== 'Kristian')
【讨论】:
我想要的另一件事,数组中的每个对象都有单独的按钮。如果我想在单击的数组按钮中删除该特定对象。怎么做 。我已经使用 Angular js ng-repeat 来生成项目。你能帮帮我吗 daCoda 如果你有两个条件怎么办? @MalcolmSalvador 例如说,如果你有其他条件,你可以像下面这样写,然后继续使用不同的 && 或 ||运营商根据您的需要。 someArray = someArray.filter(function(returnableObjects) return returnableObjects.name !== 'Kristian' && cond2Query.age >= 22; );【参考方案17】:仅返回数组中属性name
不是“Kristian”的对象
var noKristianArray = $.grep(someArray, function (el) return el.name!= "Kristian"; );
演示:
var someArray = [
name:"Kristian", lines:"2,5,10",
name:"John", lines:"1,19,26,96",
name:"Kristian", lines:"2,58,160",
name:"Felix", lines:"1,19,26,96"
];
var noKristianArray = $.grep(someArray, function (el) return el.name!= "Kristian"; );
console.log(noKristianArray);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
【讨论】:
【参考方案18】:您也可以使用地图功能。
someArray = [name:"Kristian", lines:"2,5,10",name:"John",lines:"1,19,26,96"];
newArray=[];
someArray.map(function(obj, index)
if(obj.name !== "Kristian")
newArray.push(obj);
);
someArray = newArray;
console.log(someArray);
【讨论】:
但是如果要遍历数组,用forEach不是更好吗? map() 确实遍历了一个数组。【参考方案19】:你也可以使用some
:
someArray = [name:"Kristian", lines:"2,5,10",
name:"John", lines:"1,19,26,96"];
someArray.some(item =>
if(item.name === "Kristian") // Case sensitive, will only remove first instance
someArray.splice(someArray.indexOf(item),1)
)
【讨论】:
【参考方案20】:你也可以尝试做这样的事情:
var myArray = ['name': 'test', 'name':'test2'];
var myObject = 'name': 'test';
myArray.splice(myArray.indexOf(myObject),1);
【讨论】:
myArray.indexOf(myObject)
返回 -1,因为没有项目引用等于 myObject
。所以splice()
删除了数组中的第-1 个元素,在本例中为'name':'test2'
!【参考方案21】:
这个概念使用剑道网格
var grid = $("#addNewAllergies").data("kendoGrid");
var selectedItem = SelectedCheckBoxList;
for (var i = 0; i < selectedItem.length; i++)
if(selectedItem[i].boolKendoValue==true)
selectedItem.length= 0;
【讨论】:
【参考方案22】:ES2015
let someArray = [
name:"Kristian", lines:"2,5,10",
name:"John", lines:"1,19,26,96",
name:"Kristian", lines:"2,58,160",
name:"Felix", lines:"1,19,26,96"
];
someArray = someArray.filter(person => person.name != 'John');
它将删除 John!
【讨论】:
Man...来自java,我很困惑这样一个基本的事情需要过滤列表... wtf。这是迄今为止我读到的对 OPs 问题的最准确答案。 是的,这是一个好方法。虽然它也可以在 ES2015(ES6)之前工作。过滤功能从5.1(2011)版开始可用ecma-international.org/ecma-262/5.1/#sec-15.4.4.20 漂亮干净 :)【参考方案23】:带 ES 6 箭头函数
let someArray = [
name:"Kristian", lines:"2,5,10",
name:"John", lines:"1,19,26,96"
];
let arrayToRemove=name:"Kristian", lines:"2,5,10";
someArray=someArray.filter((e)=>e.name !=arrayToRemove.name && e.lines!= arrayToRemove.lines)
【讨论】:
【参考方案24】:这是我用的。
Array.prototype.delete = function(pos)
this[pos] = undefined;
var len = this.length - 1;
for(var a = pos;a < this.length - 1;a++)
this[a] = this[a+1];
this.pop();
那就这么简单了
var myArray = [1,2,3,4,5,6,7,8,9];
myArray.delete(3);
用任意数字代替三。之后预期的输出应该是:
console.log(myArray); //Expected output 1,2,3,5,6,7,8,9
【讨论】:
你的删除功能只是splice
的一个更糟糕的版本。【参考方案25】:
如果您想删除给定对象的所有出现(基于某些条件),请在 for 循环中使用 javascript splice 方法。
由于删除对象会影响数组长度,因此请确保将计数器递减一级,以便长度检查保持不变。
var objArr=[Name:"Alex", Age:62,
Name:"Robert", Age:18,
Name:"Prince", Age:28,
Name:"Cesar", Age:38,
Name:"Sam", Age:42,
Name:"David", Age:52
];
for(var i = 0;i < objArr.length; i ++)
if(objArr[i].Age > 20)
objArr.splice(i, 1);
i--; //re-adjust the counter.
上面的代码sn -p 删除所有年龄大于20的对象。
【讨论】:
【参考方案26】:这个答案
for (var i =0; i < someArray.length; i++)
if (someArray[i].name === "Kristian")
someArray.splice(i,1);
不适用于满足条件的多个记录。如果您有两条这样的连续记录,则仅删除第一条,跳过另一条。你必须使用:
for (var i = someArray.length - 1; i>= 0; i--)
...
相反。
【讨论】:
【参考方案27】:我猜答案很复杂。
您可以使用以下路径删除与现代 JavaScript 行话中给出的对象匹配的数组对象。
coordinates = [
lat: 36.779098444109145, lng: 34.57202827508546 ,
lat: 36.778754712956506, lng: 34.56898128564454 ,
lat: 36.777414146732426, lng: 34.57179224069215
];
coordinate = lat: 36.779098444109145, lng: 34.57202827508546 ;
removeCoordinate(coordinate: Coordinate): Coordinate
const found = this.coordinates.find((coordinate) => coordinate == coordinate);
if (found)
this.coordinates.splice(found, 1);
return coordinate;
【讨论】:
【参考方案28】:这是一个带有映射和拼接的示例
const arrayObject = [
name: "name1", value: "value1" ,
name: "name2", value: "value2" ,
name: "name3", value: "value3" ,
];
let index = arrayObject.map((item) => item.name).indexOf("name1");
if (index > -1)
arrayObject.splice(index, 1);
console.log("Result", arrayObject);
输出
Result [
"name": "name2",
"value": "value2"
,
"name": "name3",
"value": "value3"
]
【讨论】:
这也可以在 IE11 中使用,而使用findIndex
的答案则不行。【参考方案29】:
性能
今天 2021 年 1 月 27 日,我在 Chrome v88、Safari v13.1.2 和 Firefox v84 上对 MacOs HighSierra 10.13.6 执行所选解决方案的测试。
结果
适用于所有浏览器:
元素不存在时的快速/最快解决方案:A 和 B 快速/最快的大型阵列解决方案:C 当元素存在时大数组的快速/最快解决方案:H 小阵列的相当慢的解决方案:F 和 G 大型阵列的相当慢的解决方案:D、E 和 F详情
我执行了 4 个测试用例:
小数组(10 个元素)和元素存在 - 你可以运行它HERE 小数组(10 个元素)和元素不存在 - 你可以运行它HERE 大数组(百万元素)和元素存在 - 你可以运行它HERE 大数组(百万元素)和元素不存在 - 你可以运行它HERE下面的 sn-p 显示了解决方案之间的差异 A B C D E F G H I
function A(arr, name)
let idx = arr.findIndex(o => o.name==name);
if(idx>=0) arr.splice(idx, 1);
return arr;
function B(arr, name)
let idx = arr.findIndex(o => o.name==name);
return idx<0 ? arr : arr.slice(0,idx).concat(arr.slice(idx+1,arr.length));
function C(arr, name)
let idx = arr.findIndex(o => o.name==name);
delete arr[idx];
return arr;
function D(arr, name)
return arr.filter(el => el.name != name);
function E(arr, name)
let result = [];
arr.forEach(o => o.name==name || result.push(o));
return result;
function F(arr, name)
return _.reject(arr, el => el.name == name);
function G(arr, name)
let o = arr.find(o => o.name==name);
return _.without(arr,o);
function H(arr, name)
$.each(arr, function(i)
if(arr[i].name === 'Kristian')
arr.splice(i,1);
return false;
);
return arr;
function I(arr, name)
return $.grep(arr,o => o.name!=name);
// Test
let test1 = [
name:"Kristian", lines:"2,5,10",
name:"John", lines:"1,19,26,96",
];
let test2 = [
name:"John3", lines:"1,19,26,96",
name:"Kristian", lines:"2,5,10",
name:"John", lines:"1,19,26,96",
name:"Joh2", lines:"1,19,26,96",
];
let test3 = [
name:"John3", lines:"1,19,26,96",
name:"John", lines:"1,19,26,96",
name:"Joh2", lines:"1,19,26,96",
];
console.log(`
Test1: original array from question
Test2: array with more data
Test3: array without element which we want to delete
`);
[A,B,C,D,E,F,G,H,I].forEach(f=> console.log(`
Test1 $f.name: $JSON.stringify(f([...test1],"Kristian"))
Test2 $f.name: $JSON.stringify(f([...test2],"Kristian"))
Test3 $f.name: $JSON.stringify(f([...test3],"Kristian"))
`));
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"> </script>
This shippet only presents functions used in performance tests - it not perform tests itself!
以下是 chrome 的示例结果
【讨论】:
【参考方案30】:如果您在数组中的对象上没有任何您知道(或者可能是唯一的)的属性,但是您有对要删除的对象的引用,则可以执行 @987654321 中的操作@方法如下:
let registeredObjects = [];
function registerObject(someObject) registeredObjects.push(someObject);
function unregisterObject(someObject) registeredObjects = registeredObjects.filter(obj => obj !== someObject);
let myObject1 = hidden: "someValue1"; // Let's pretend we don't know the hidden attribute
let myObject2 = hidden: "someValue2";
registerObject(myObject1);
registerObject(myObject2);
console.log(`There are $registeredObjects.length objects registered. They are: $JSON.stringify(registeredObjects)`);
unregisterObject(myObject1);
console.log(`There are $registeredObjects.length objects registered. They are: $JSON.stringify(registeredObjects)`);
【讨论】:
以上是关于使用 JavaScript 从数组中删除对象的主要内容,如果未能解决你的问题,请参考以下文章
使用 jquery 表中的复选框从数组中删除 JavaScript 对象
使用jquery表中的复选框从数组中删除JavaScript对象