获取对象数组中的重复项

3

我有一个对象数组。

let coordinates = [
    { x: 8, y: 1 },
    { x: 8, y: 3 },
    { x: 6, y: 5 },
    { x: 4, y: 6 },
    { x: 3, y: 7 },
    { x: 6, y: 5 },
    { x: 3, y: 3 },
    { x: 1, y: 4 },
    { x: 3, y: 3 }
]

我偶然发现了这篇博客和这个stackoverflow问题,但是它们仅允许我基于一个属性查找重复项,而我想根据xy属性获取重复对象,就像这样:

[    { x: 6, y: 5 },    { x: 3, y: 3 }]

预期结果是什么? - brk
1
@brk 它在我问题的最后一部分。 - breekoy
4个回答

2

我们应用过滤器来检查索引的唯一性,如果元素是重复的,它将计算初始索引并过滤掉当前索引。

var coordinates = [ { x: 8, y: 1 }, { x: 6, y: 5 }, { x: 4, y: 6 }, { x: 3, y: 7 }, { x: 6, y: 5 }, { x: 3, y: 3 }, { x: 1, y: 4 }, { x: 3, y: 3 }];

var result = coordinates.filter((val, i, self)=>self.findIndex(k=>k.x==val.x && k.y == val.y)!=i);

console.log(result)

更新

coordinates = [ { x: 6, y: 5 }, { x: 6, y: 5 }, { x: 6, y: 5 },{ x: 4, y: 6 }, { x: 3, y: 7 }, { x: 6, y: 5 }, { x: 3, y: 3 }, { x: 3, y: 3 }, { x: 1, y: 4 }, { x: 3, y: 3 },{ x: 6, y: 5 }];

result = coordinates.reduce((acc, elem)=>{
  key = Object.values(elem).join('|');
  acc.unique[key] = acc.unique[key] || [];
  acc.unique[key].length >0 ? acc.duplicate[key] = elem : acc.unique[key].push(elem);
  return acc;
},{unique:{},duplicate:{}});

duplicate = Object.values(result.duplicate);
unique = Object.values(result.unique);

console.log(duplicate);
console.log(unique);


@breekoy 如果你看一下 filter 函数,它接受各种参数,如 (val, i, self)。其中 val 表示当前迭代元素,i 表示索引计数,而 self 则是数组本身。 - gorak
1
这是错误的答案。它无法处理包含重复项超过2个的数组,例如var coordinates = [ { x: 3, y: 3 }, { x: 3, y: 3 }, { x: 3, y: 3 }, ] - Jsowa

1
你可以使用 reduce 和另一个数组。在 reduce 回调函数中,使用 x 和 y 创建一个对象键,并检查该键是否存在于累加器对象中。如果存在,则将该值推送到 dupArray

let coordinates = [
  { x: 8, y: 1 },
  { x: 8, y: 3 },
  { x: 6, y: 5 },
  { x: 4, y: 6 },
  { x: 3, y: 7 },
  { x: 6, y: 5 },
  { x: 3, y: 3 },
  { x: 1, y: 4 },
  { x: 3, y: 3 }
];
let dupArray = [];
let dups = coordinates.reduce((acc, curr) => {
  const crtKey = '' + curr.x + '' + curr.y;
  if (!acc[crtKey]) {
    acc[crtKey] = 1;
  } else {
    dupArray.push(curr);
  }
  return acc;
}, {});

console.log(dupArray)


我认为在 + curr.x 之前的第一个 '' 是多余的。 - zb22
@zb22 因为我想要键是字符串,否则键将是数字。例如,像9(6+3)或9(5+4)这样的键将是相同的,这将导致错误的结果。 - brk
是的,但是 curr.x + '' + curr.y 会使其变成字符串,一旦在它们之间加上 '' - zb22
1
这个答案还会出现超过2个重复的情况 var coordinates = [ { x: 3, y: 3 }, { x: 3, y: 3 }, { x: 3, y: 3 }, ] - Jsowa
1
当我们想要重复项时,这是直观的,我们不需要重复的重复项。只需要唯一的重复项。 - Jsowa
显示剩余5条评论

1

所有答案都不完全正确,因为它们不适用于具有两个以上相同值的数组,即:

var coordinates = [
  { x: 8, y: 1 },
  { x: 8, y: 1 },
  { x: 8, y: 1 }
]

我使用了JSON.stringify()和Set结构从数组中获取唯一的重复项。而对于输出,我将字符串解析回对象。

var coordinates = [
      { x: 8, y: 1 },
      { x: 6, y: 5 },
      { x: 4, y: 6 },
      { x: 3, y: 7 },
      { x: 6, y: 5 },
      { x: 3, y: 3 },
      { x: 1, y: 4 },
      { x: 3, y: 3 },
      { x: 3, y: 3 },
]
    
const duplicates = new Set();
const reducer = (set, val, index, arr) => arr.findIndex(k => k.x == val.x && k.y == val.y) != index ? set.add(JSON.stringify(val)) : set
    
coordinates.reduce(reducer, duplicates)
    
console.log(Array.from(duplicates).map(el => JSON.parse(el)))


0

这个函数通过迭代所有数组项,并对每个项再次迭代数组(使用some),检查特定项是否在当前项(idx1)之前的位置(arr)中出现过,同时将当前项与some iterator中的已检查项进行比较,将两者都转换为"string",从而仅过滤重复的数组对象。

let coordinates = [
    { x: 8, y: 1 },
    { x: 8, y: 3 },
    { x: 6, y: 5 },
    { x: 4, y: 6 },
    { x: 3, y: 7 },
    { x: 6, y: 5 },
    { x: 3, y: 3 },
    { x: 1, y: 4 },
    { x: 3, y: 3 }
]

const dups = coordinates.filter(({x, y}, idx1, arr) => 
    arr.some(({x:x2,y:y2}, idx2) => idx2 < idx1 && ""+x+y == ""+x2+y2 ) 
)

console.log( dups )

为了使检查更加健壮,可以比较任何键,可以使用JSON.stringify来比较数组(假设所有数组项都是对象)。
const dups = coordinates.filter((item, idx1, arr) => 
   arr.some((item2, idx2) => idx2 < idx1 && JSON.stringify(item) == JSON.stringify(item2)) 

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