【问题标题】:Deleting from arrays with object by value按值从具有对象的数组中删除
【发布时间】:2014-05-06 03:29:53
【问题描述】:

我有一个这样的对象

myArray = [
              { name: "1",
                age: "20"
               },         
              { name: "6",
                age: "20"
               },  
              { name: "2",
                age: "20"
               },  
             ];

  anotherArray = [2,1,3,4,5,6];

基本上我试图找到匹配 a 是否存在,如果存在则从myArray中删除它

    for(var i = 0, len = myArray.length; i < len; i++) {
      var searchTerm = myArray[i].name;
      for (var j = 0; j < anotherArray.length; j++) {
      if (myArray[i].name === anotherArray[j]) {
        // Not exactly sure how the deletion will work with array.splice
        len--;
        break;
    }
   }
  }

由于某种原因,它似乎没有按预期工作。

最终的结果应该是这样的

   myArray = [         
              { name: "6",
                age: "20"
               } 
             ];

【问题讨论】:

  • 请注意,如果拼接出当前成员,则需要减少计数器并缩短迭代限制,因为长度也会更短。反向迭代更简单,所以这些都不是问题。
  • 或者使用filterindexOf的组合,比如arr1.filter(function(x){return ~arr2.indexOf(x.name)}
  • @elclanrs 哦~可读性! =)(不过我喜欢这个解决方案)
  • @elclanrs — indexOf 使用=== 所以"1" !== 1。 :-)

标签: javascript arrays javascript-objects


【解决方案1】:

这里有几件事会给你带来麻烦。一方面,使用字符串相等运算符=== 将阻止任何类型的类型强制执行,这意味着"1"1 将不相等。如果您希望执行类型转换,您应该使用== 相等运算符:

"1" === 1;
=> false

"1" == 1;
=> true

此外,在我看来,您使用这种方法过于复杂了。如果您希望从数组中删除名称包含在anotherArray 中的所有对象,您应该使用标准的Array.prototype.filter 方法来生成您想要的数组:

var myArray = [{name: "1", age: "20"}, 
               {name: "6", age: "20"}, 
               {name: "2", age: "20"}],
    anotherArray = [2,1,3,4,5,6];

myArray = myArray.filter(function(e) {
 return (a.indexOf(e.name|0) < 0)   // note: e.name|0 will convert the string 
});                                 // value of e.name to an integer
=> [];

关于您发布的代码的几点注意事项:

  1. 因为anotherArray 的声明没有前面的var 并且不是逗号分隔的var 语句的一部分,所以它将被实例化为一个全局 变量。这种行为是非常不可取的,可能会导致代码中出现一些非常奇怪的错误。
  2. 您表示您希望删除的结果会产生以下数组:

    myArray = [{name: "6", age: "20"}]

    但是,请注意 6anotherArray 中的一个元素,因此您的结果数组实际上应该是空的。

【讨论】:

  • 请注意,name 是一个字符串,但 anotherArray 中的值是数字,因此它们不会使用 indexOf 进行匹配。
  • @RobG 你是对的,但是表达式e.name|0 使用按位或将e.name 转换为整数。这与您使用一元 + 的操作非常相似
  • 啊,是的,错过了。可能已经看到+e.name。 :-)
【解决方案2】:

您正在比较两个不同的事物(类型),因为 myArray[i].name 是 String 对象, anotherArray[j] 是 Number 对象。您应该转换其中之一或使用相等运算符 ("=="),而不是严格相等运算符 ("===")。如需进一步参考,请参阅MDN

即使它可能被视为糟糕的代码,您也可以使用 delete 关键字删除(正如 @RobG 所记得的,它不会改变长度,留下一个空引用):

...
if (myArray[i].name === anotherArray[j]) {
    delete myArray[i];
...

Array.prototype.filter 应该这样做:

myArray.filter(function(i) { return Array.prototype.indexOf([2,1,3,4,5,6], i.name) })

但结果将包含名称在 [1,2,6] 中的对象

【讨论】:

  • 讨厌,索引 2 处没有成员(即[{...}, , {...}]),所以长度仍然是 3。
  • @RobG 不,它没有。你用的是什么浏览器?
  • 确实如此,delete operator 没有做任何特殊的事情(像数组方法那样),例如调整数组的长度或其他成员的索引。
  • 对不起...我虽然你在谈论另一个...确定删除你是对的...我的错...;P
  • 是否存在问题取决于其他代码的健壮性。大多数人都假设紧凑的数组,所以最好不要稀疏地喂它们。 :-)
【解决方案3】:

有几个问题。 myArray 数组文字中的尾随逗号在 IE 中被错误地视为省略号,因此数组的长度过长。另外,anotherArray 包含 myArray 的所有成员,所以如果该函数有效,它会删除所有成员。

您可以使用 splice 从数组中删除成员。它会影响长度,并且在递增循环中意味着如果您不修改计数器,您将跳过下一个成员。通常的策略是使用递减循环来避免这些问题。

最后,"name" 属性是一个字符串,但 anotherArray 中的值是数字,这可能会影响比较。

myArray = [
              { name: "1",
                age: "20"
               },         
              { name: "6",
                age: "20"
               },  
              { name: "2",
                age: "20"
               }                   // trailing comma removed
             ];

  anotherArray = [2,1,3,4,5];  // 6 removed so one member remains


for (var i=myArray.length - 1; i >= 0; i--) {
  // Convert name to a number since indexOf uses ===
  if (anotherArray.indexOf(+myArray[i].name) != -1) {
    myArray.splice(i, 1);
  }
}

console.log(myArray[0].name);

indexOf 的 polyfill 可以在 MDN 找到。

【讨论】:

    猜你喜欢
    • 2021-11-17
    • 2021-10-26
    • 2020-08-28
    • 2018-09-26
    • 1970-01-01
    • 2021-06-07
    • 2019-03-29
    • 1970-01-01
    • 2022-07-27
    相关资源
    最近更新 更多