0

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

6
  • @NinaScholz sorry. Updated the OP Commented Jun 16, 2020 at 17:31
  • does this answer your question? stackoverflow.com/questions/9229645/… Commented Jun 16, 2020 at 17:35
  • do you have only duplicates with two same id? Commented Jun 16, 2020 at 17:38
  • Get an object with each id as key and count for that keys as value. filter all the items with count = 1. Commented Jun 16, 2020 at 17:39
  • @NinaScholz yeah. I am basically pushing an object into an array and removing the duplicates Commented Jun 16, 2020 at 17:55

8 Answers 8

2

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);

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks @Nina. That worked. Can you help me figure this out? stackblitz.com/edit/react-ts-a9pgna?file=ValidateFile.tsx I am able to add items but unable to remove them to the list.
@a2441918, i have no idea. please ask a new question.
1

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));

1 Comment

Could you help me out here as well? stackblitz.com/edit/react-ts-a9pgna?file=ValidateFile.tsx I am able to add items but unable to remove them
0

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)

2 Comments

This is not what OP is asking. They want to remove all the objects of an id if an id appears more than once.
exactly. You'll keep adding it to a reducer object by a key name: so reducer[1] = {id: 1}, overwriting previous value every time and end up with an object containing list of unique values;
0

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)


Comments

0

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);

Comments

0

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}

Comments

0

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

Comments

0

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.