获取对象数组中重复对象的列表

IT技术 javascript arrays typescript ecmascript-6 lodash
2021-03-07 06:34:24

我试图在对象数组中获取重复的对象。假设对象如下所示。

values = [
  { id: 10, name: 'someName1' },
  { id: 10, name: 'someName2' },
  { id: 11, name: 'someName3' },
  { id: 12, name: 'someName4' }
];

重复的对象应该返回如下:

duplicate = [
  { id: 10, name: 'someName1' },
  { id: 10, name: 'someName2' }
];
6个回答

您可以使用Array#reduce基于id的计数器查找表,然后用于Array#filter删除查找表中仅出现一次的任何项目。时间复杂度为 O(n)。

const values = [{id: 10, name: 'someName1'}, {id: 10, name: 'someName2'}, {id: 11, name:'someName3'}, {id: 12, name: 'someName4'}];

const lookup = values.reduce((a, e) => {
  a[e.id] = ++a[e.id] || 0;
  return a;
}, {});

console.log(values.filter(e => lookup[e.id]));

我建议您查看文档reducefilter如果您还没有。reduce用来构建每个对象id到其occurrences - 1. a是从一个回调传递到下一个回调的累加器对象reducefilter使用 的真实性lookup[e.id]来确定元素是否唯一。如果查找条目为 0 (falsey),则它只出现一次并filter从结果集中忽略它,否则它会被保留。
2021-04-17 06:34:24
其实我知道reduce(不是专家,但知道)和过滤器。并且知道它们是如何工作的。但是很难理解你的代码。但是有了你的解释,一切都变得容易了:)谢谢。
2021-05-05 06:34:24
@ggorlen 我们可以比较多个字段 ID 和名称吗?
2021-05-05 06:34:24
这是非常聪明的代码,我认为您的解释不正确@ggorlen!为了准确解释reduce内部发生的事情,这里是:数组中的每个项目都由箭头函数处理,并且要么在查找​​中创建一个属性(新项目),要么增加计数器(我们遇到重复项)。其工作原理如下: a[e.id] = ++a[e.id] || 0 只会使用 ++ 增加属性,如果它已经存在。如果不是,则它将通过 OR (||) 并创建值为 0 的属性。
2021-05-08 06:34:24
你能解释一下你的代码吗?我很困惑。你的代码中没有任何平等是如何工作的?为什么a在每次迭代中都显示相同的对象?我需要对你的代码进行详细分析。
2021-05-10 06:34:24

假设你有:

arr = [
    { id:10, name: 'someName1' },
    { id:10, name: 'someName2' },
    { id:11, name: 'someName3' },
    { id:12, name: 'someName4' }
]

因此,要获得独特的物品:

unique = arr
     .map(e => e['id'])
     .map((e, i, final) => final.indexOf(e) === i && i)
     .filter(obj=> arr[obj])
     .map(e => arr[e]);

那么,结果将是

unique = [
     { id:10, name: 'someName1' },
     { id:11, name: 'someName3' },
     { id:12, name: 'someName4' }
]

并且,要获得重复的 ID:

duplicateIds = arr
     .map(e => e['id'])
     .map((e, i, final) => final.indexOf(e) !== i && i)
     .filter(obj=> arr[obj])
     .map(e => arr[e]["id"])

ID 列表将是

duplicateIds = [10]

因此,要获取重复的对象:

duplicate = arr.filter(obj=> dublicateIds.includes(obj.id));

现在你拥有了:

duplicate = [
    { id:10, name: 'someName1' },
    { id:10, name: 'someName2' }
]

谢谢https://reactgo.com/removeduplicateobjects/

感谢您的回复,我在您的回答中使用了完全相同的示例。在您的示例中,我们根据 ID 找出重复项。如果我们必须找出重复的 ID 和 name 属性,需要做哪些更改?任何帮助,将不胜感激
2021-04-18 06:34:24
您可以通过将“.map(e => e['id'])”替换为“.map(e => e['id']+'_'+e['name'])”来轻松做到这一点
2021-04-26 06:34:24
我不是你的意思@Vivek,如果你有输入和预期输出的例子,那么我可以提供帮助!
2021-05-01 06:34:24
我们如何找出多个属性的重复项?
2021-05-07 06:34:24
我们如何称呼它?
2021-05-13 06:34:24

您还没有澄清两个具有不同 id 的对象,但相同的“名称”是否算作重复。我会假设那些不算作重复;换句话说,只有具有相同 id 的对象才算作重复。

let ids = {};
let dups = [];

values.forEach((val)=> {
  if (ids[val.id]) {
    // we have already found this same id
    dups.push(val)
  } else {
    ids[val.id] = true;
  }
})
return dups;

随着lodash你可以解决这个问题filter,并countBy为复杂性O(n)

const data = [{ id: 10,name: 'someName1' }, { id: 10,name: 'someName2' }, { id: 11,name: 'someName3' }, { id: 12,name: 'someName4' } ]

const counts = _.countBy(data, 'id')
console.log(_.filter(data, x => counts[x.id] > 1))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

你可以像这样对 ES6 做同样的事情:

const data = [{ id: 10,name: 'someName1' }, { id: 10,name: 'someName2' }, { id: 11,name: 'someName3' }, { id: 12,name: 'someName4' } ]

const countBy = (d, id) => d.reduce((r,{id},i,a) => (r[id] = a.filter(x => x.id == id).length, r),{})
const counts = countBy(data, 'id')
console.log(data.filter(x => [x.id] > 1))

您可以使用数组来存储唯一元素,并对值使用过滤器以仅返回重复项。

const unique = []

const duplicates = values.filter(o => {

   if(unique.find(i => i.id === o.id && i.name === o.name)) {
     return true
   }

   unique.push(o)
   return false;
})