使用 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);
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

【讨论】:

【参考方案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 对象

从 JSON 使用 Javascript 创建动态关联数组

使用jquery表中的复选框从数组中删除JavaScript对象

从对象数组中删除元素javascript

jQuery / Javascript从对象数组中删除一个对象[重复]

如何从 JavaScript 关联数组中删除对象?