按照对象属性过滤数组,使其只包含唯一的对象。

17
我想要实现的是对“objects”数组进行过滤,以便获得具有唯一演员的对象数组。
所以这是我目前拥有的:

var objects = [{
    actor: {
      account: null,
      degraded: false,
      mbox: null,
      mbox_sha1sum: "843c56da78f9eb888274d2d4e12ab1d748ec46234",
      name: "name",
      openid: null
    },
    capture: 'value'
  },
  {
    actor: {
      account: null,
      degraded: false,
      mbox: null,
      mbox_sha1sum: "843c56da78f9eb888274d2d4e12ab1d748ec12345",
      name: "name2",
      openid: null
    },
    capture: 'value2'
  },
  {
    actor: {
      account: null,
      degraded: false,
      mbox: null,
      mbox_sha1sum: "843c56da78f9eb888274d2d4e12ab1d748ec46234",
      name: "name",
      openid: null
    },
    capture: 'value3'
  }
];


objects.filter((value, index, self) => {
  return self.indexOf(value) === index;
}).map(ele => {
  console.log(ele.capture);
});

期望的结果是一个数组,其中不包括最后一个数组元素,因为此演员属性与第一个数组元素匹配。但是目前它没有过滤任何数组元素。起初我以为 return self.indexOf(value.value) === index; 会解决这个问题,但是它返回了一个空数组。
[{
    actor: {
      account: null,
      degraded: false,
      mbox: null,
      mbox_sha1sum: "843c56da78f9eb888274d2d4e12ab1d748ec46234",
      name: "name",
      openid: null
    },
    capture: 'value'
  },
  {
    actor: {
      account: null,
      degraded: false,
      mbox: null,
      mbox_sha1sum: "843c56da78f9eb888274d2d4e12ab1d748ec12345",
      name: "name2",
      openid: null
    },
    capture: 'value2'
  }
];

预期结果是什么? - guest271314
@guest271314 我会更新问题,包括预期结果。 - Zze
2个回答

33

即使某些对象具有相同值的属性,您数组中的对象仍然是不同的对象。 .indexOf() 函数比较的是引用而不是属性值。

此外,在实践中,这三个对象都具有不同的 .capture 值,因此它们没有完全相同的属性。

请使用 .findIndex() 代替 .indexOf(),这样您就可以比较属性以查找匹配的对象:

objects.filter((value, index, self) => {
  return self.findIndex(v => v.actor.name === value.actor.name) === index;
})

这里我只是使用了.actor.name属性,但当然如果需要的话,您可以比较其他属性。

(请注意.findIndex()是ES6函数,但是假设您的代码已经使用箭头函数,那么应该没问题。或者您可以填充它。)

var objects = [{
    actor: {
      account: null,
      degraded: false,
      mbox: null,
      mbox_sha1sum: "843c56da78f9eb888274d2d4e12ab1d748ec46234",
      name: "name",
      openid: null
    },
    capture: 'value'
  },
  {
    actor: {
      account: null,
      degraded: false,
      mbox: null,
      mbox_sha1sum: "843c56da78f9eb888274d2d4e12ab1d748ec12345",
      name: "name2",
      openid: null
    },
    capture: 'value2'
  },
  {
    actor: {
      account: null,
      degraded: false,
      mbox: null,
      mbox_sha1sum: "843c56da78f9eb888274d2d4e12ab1d748ec46234",
      name: "name",
      openid: null
    },
    capture: 'value3'
  }
];


objects.filter((value, index, self) => {
  return self.findIndex(v => v.actor.name === value.actor.name) === index;
}).map(ele => {
  console.log(ele.capture);
});


请注意,这完全回答了我的问题,上面的评论只是好奇心。 - Zze
1
你有不同的对象实例,它们恰好具有相同的属性值。这与拥有相同的对象不是一回事。因此,===.indexOf() 比较引用,即使它们看起来相同,{} === {} 总是 false。而且,你的三个数组元素都不相同,因为它们都具有不同的.capure 值。 - nnnnnn
那有点超出我的理解范围,我需要更多的研究。非常感谢你的出色回答,非常感激。 - Zze
2
我会尝试用稍微不同的方式来表达:var x = {name:'Fred'}; var y = {name:'Fred'}; 创建了两个独立的对象。当你说 x == y 时,它是 false,因为 xy 不引用内存中的同一对象,它们引用分别具有相同 .name 的不同对象。 - nnnnnn
很棒。扩展上一个例子,如果你接着说 var z = x,那么就会创建一个新的变量 z,它现在指向与 x 相同的对象,而不是创建该对象的副本。因此,x == z 将为 true(相同的对象),但 y == z 将为 false(不同的对象,只是名称相同)。如果一开始有点困惑,不用担心,你会掌握的。 - nnnnnn
显示剩余3条评论

0

如果您可以使用对象字面量来过滤唯一元素。

var objects = [{
    actor: {
      account: null,
      degraded: false,
      mbox: null,
      mbox_sha1sum: "843c56da78f9eb888274d2d4e12ab1d748ec46234",
      name: "name",
      openid: null
    },
    capture: 'value'
  },
  {
    actor: {
      account: null,
      degraded: false,
      mbox: null,
      mbox_sha1sum: "843c56da78f9eb888274d2d4e12ab1d748ec46234",
      name: "name",
      openid: null
    },
    capture: 'value3'
  }
];

const uniqueObjMap = {};
for (const object of objects) {
  uniqueObjMap[object.actor.name] = object;
}

const uniqueObjects = Object.values(uniqueObjMap);
console.log(uniqueObjects)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接