arunmmanoharan
arunmmanoharan

Reputation: 2675

Remove original and duplicate from an array of objects - JS

I have an array of objects.

const arr = [
  { title: "sky", artist: "Jon", id: 1 },
  { title: "rain", artist: "Paul", id: 2 },
  { title: "sky", artist: "Jon", id: 1 }
];

I would like to remove all duplicates from the array based on id. The final result should be

[{ title: "rain", artist: "Paul", id: 2 }]

If the array is

const arr = [
  { title: "sky", artist: "Jon", id: 1  },
  { title: "rain", artist: "Paul", id: 2  },
  { title: "sky", artist: "Jon", id: 1  },
  { title: "rain", artist: "Paul", id: 2  },
];

The result should be an [].

This is what I tried:

const arr = [{
    title: "sky",
    artist: "Jon",
    id: 1
  },
  {
    title: "rain",
    artist: "Paul",
    id: 2
  },
  {
    title: "sky",
    artist: "Jon",
    id: 1
  }
];
const uniqueScenarios = Array.from(new Set(arr.map(a => a.id)))
  .map(id => {
    return arr.find(a => a.id === id)
  })

console.log(uniqueScenarios)

const arr1 = [{
    title: "sky",
    artist: "Jon",
    id: 1
  },
  {
    title: "rain",
    artist: "Paul",
    id: 2
  },
  {
    title: "sky",
    artist: "Jon",
    id: 1
  },
  {
    title: "rain",
    artist: "Paul",
    id: 2
  }
];
const uniqueScenarios1 = Array.from(new Set(arr1.map(a => a.id)))
  .map(id => {
    return arr1.find(a => a.id === id)
  })

console.log(uniqueScenarios1)

Please advice. I am open to lodash solutions as well. This is the final solution I am expecting. I am able to add Stackblitz link

Upvotes: 0

Views: 130

Answers (8)

ABGR
ABGR

Reputation: 5205

If you know the title, artist, id are gonna be in the same order in each of the object, one solution can be this:

var arrayX=[
  { title: "sky", artist: "Jon", id: 1 },
  { title: "rain", artist: "Paul", id: 2 },
  { title: "sky", artist: "Jon", id: 1 }
];
var newArray = arrayX.map(i=> JSON.stringify(i)); //stringify all the objects so as to compare them
var res = newArray.filter((elem, index)=>{
  if(newArray.indexOf(elem) === newArray.lastIndexOf(elem)){
    return elem //get only those elements whihc do not have dupes
  }
}); 
var finalResult = res.map(i=>JSON.parse(i)); //parse the result to get the array of object
console.log(finalResult)

Upvotes: 0

Ori Drori
Ori Drori

Reputation: 191976

You can group the items by id, and then use _.flatMap() to convert back a single array. In the _.flatMap() callback return an empty array if the group has more than one item:

const fn = arr => _.flatMap(
  _.groupBy(arr, 'id'), // group by the id
  group => _.size(group) > 1 ? [] : group // check the size and return an empty array for groups with more than a single item
)

const arr1 = [{"title":"sky","artist":"Jon","id":1},{"title":"rain","artist":"Paul","id":2},{"title":"sky","artist":"Jon","id":1}]
const arr2 = [{"title":"sky","artist":"Jon","id":1},{"title":"rain","artist":"Paul","id":2},{"title":"sky","artist":"Jon","id":1},{"title":"rain","artist":"Paul","id":2}]

console.log(fn(arr1))
console.log(fn(arr2))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

Another example

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386560

You could take an object and filter with the value of the hash table.

const
    array = [{ title: "sky", artist: "Jon", id: 1 }, { title: "rain", artist: "Paul", id: 2 }, { title: "sky", artist: "Jon", id: 1 }, { title: "rain", artist: "Paul", id: 2 }],
    ids = array.reduce((r, { id }) => (r[id] = !(id in r), r), {}),
    result = array.filter(({ id }) => ids[id]);

console.log(result);

Upvotes: 2

Ehsan Nazeri
Ehsan Nazeri

Reputation: 801

you can sort the data by id,then each item that has different id compared with next element and prev element should be added to the result array.

const arr = [
  { title: 'sky', artist: 'Jon', id: 1 },
  { title: 'rain', artist: 'Paul', id: 2 },
  { title: 'sky', artist: 'Jon', id: 1 },
  { title: 'sky', artist: 'Jon', id: 1 },
  { title: 'rain', artist: 'Paul', id: 2 },
  { title: 'test', artist: 'test', id: 3 },
]

arr.sort((a, b) => a.id - b.id)
var res = []
arr.forEach((item, index) => {
  if (index < arr.length - 1 && arr[index + 1]) {
    if (item.id === arr[index + 1].id) {
      return
    }
  }
  if (index > 0 && arr[index - 1]) {
    if (item.id === arr[index - 1].id) {
      return
    }
  }
  res.push(item)
})

console.log(res)

output

0: {title: "test", artist: "test", id: 3}

Upvotes: 0

Samuel Goldenbaum
Samuel Goldenbaum

Reputation: 18909

You could run the array through reduce() and then use some to see if you should add if it does not exist, or remove using filter if it does.

Snippet:

const arr = [
  { title: "sky", artist: "Jon", id: 1  },
  { title: "rain", artist: "Paul", id: 2  },
  { title: "sky", artist: "Jon", id: 1  },
  { title: "rain", artist: "Paul", id: 2  },
  { title: "earth", artist: "Frank", id: 3  },
];

const unique = arr.reduce((accumulator, currentValue) => { 
  // add if we don't have
  if (!accumulator.some(x => x.id === currentValue.id)) {
    accumulator.push(currentValue);
  } else {
    // remove if we do
    accumulator = accumulator.filter(x => x.id !== currentValue.id);
  }
  
  return accumulator;
}, []); 

console.info(unique);

Upvotes: 0

Saurabh Singh
Saurabh Singh

Reputation: 132

you can do it in one line like this:

const res = arr.filter(elem => (arr.filter(obj => obj.id === elem.id)).length === 1)

or you can do it like this(better in terms of time complexity):

const arr = [
  { title: "sky", artist: "Jon", id: 1  },
  { title: "rain", artist: "Paul", id: 2  },
  { title: "sky", artist: "Jon", id: 1  },

];

const counts = arr.reduce((counts, curr) => (counts[curr.id] = ++counts[curr.id] || 1, counts), {})
const res = arr.filter(curr => counts[curr.id] === 1)


Upvotes: 0

Dmitriy Godlevski
Dmitriy Godlevski

Reputation: 620

One way to do it, in order to avoid running an exponential loop is to save all values to a new object, and convert that object to a new array.

const combinedObj = arr.reduce((obj, item) => { obj[item.id] = item; return obj; }, {});
const newArray = Object.values(combinedObj)

Upvotes: 0

Balastrong
Balastrong

Reputation: 4464

That's a one-liner:

list.filter(el => list.filter(e => e.title == el.title).length == 1);

const arr = [{
    title: "sky",
    artist: "Jon",
    id: 1
  },
  {
    title: "rain",
    artist: "Paul",
    id: 2
  },
  {
    title: "sky",
    artist: "Jon",
    id: 1
  }
];

const arr1 = [{
    title: "sky",
    artist: "Jon",
    id: 1
  },
  {
    title: "rain",
    artist: "Paul",
    id: 2
  },
  {
    title: "sky",
    artist: "Jon",
    id: 1
  },
  {
    title: "rain",
    artist: "Paul",
    id: 2
  }
];


function removeDupes(list) {
  return list.filter(el => list.filter(e => e.id == el.id).length == 1);
}

console.log(removeDupes(arr));
console.log(removeDupes(arr1));

Upvotes: 1

Related Questions