Shivam
Shivam

Reputation: 2248

Get duplicates except first occurrence in array of objects

I want to be able to return duplicates except first occurance in an array of objects based of the place and keyword. Both should match and return the documents in an new array. Here is my trial run:

var things = [
                {place: 'hello', keyword: 'hey', id: 0},
                {place: 'hi', id: 1},
                {place: 'hello', keyword: 'hey', id: 2},
                {place: 'hello', keyword: 'man', id: 3}
            ]
var duplicates = [];

things.forEach((item, index) => {
    if(things.indexOf(item.place) != index && things.indexOf(item.keyword) != index) {
        duplicates.push(item);
    }
});

Expected output:

[{place: 'hello', keyword: 'hey', id: 2}]

Any help would be great (without any frameworks, just ES6 or older). Thanks

EDIT: It should match multiple specified values such as keyword and place.

Upvotes: 1

Views: 454

Answers (3)

Nina Scholz
Nina Scholz

Reputation: 386654

You could count the same keys and filter if the count is greater than one with an object for counting

const
    getKey = o => keys.map(k => o[k]).join('|'),
    keys = ['place', 'keyword'],
    things = [{ place: 'hello', keyword: 'hey', id: 0 }, { place: 'hi', id: 1 }, { place: 'hello', keyword: 'hey', id: 2 }, { place: 'hello', keyword: 'man', id: 3 }],
    hash = Object.create(null),
    duplicates = things.filter(o =>
        (k => (hash[k] = (hash[k] || 0) + 1) > 1)
        (getKey(o))
    );
  
console.log(duplicates);

Upvotes: 2

adiga
adiga

Reputation: 35222

You could group the items based on place and then get the first item from those groups with length > 1

const things = [{ place: 'hello', keyword: 'hey', id: 0 }, { place: 'hi', id: 1 }, { place: 'hello', keyword: 'hey', id: 2 }, { place: 'hello', keyword: 'man', id: 3 }];

const merged = things.reduce((r, a) => {
  (r[a.place] = r[a.place] || []).push(a)
  return r
}, {})

const final = Object.values(merged)
                    .filter(a => a.length > 1)
                    .map(a => a[1])

console.log(final)

Upvotes: 0

Nick Brady
Nick Brady

Reputation: 6582

The obvious solution is that you'll have to track the objects you have seen in order to do it how you want.

const seen = [];
const duplicates = [];

things.forEach(item => {
  const sawItem = seen.find(seenItem => item.place === seenItem.place && item.keyword === seenItem.keyword)
  if (sawItem) {
     duplicates.push(sawItem);
  } else {
    seen.push(sawItem);
  }
});

This isn't a very efficient algorithm however, so I'm curious to see a better way to do it.

Upvotes: 0

Related Questions