The other day at work I was faced with what I think is a rather common problem when dealing with data coming from an API.
I was getting from my as...
For further actions, you may consider blocking this person and/or reporting abuse
Without getting into cryptic one-liners, there's a pretty straight forward linear time solution as well.
Hey Matt, nice solution! Yeah, all ways leads to Rome :)
Well... yes and no.
I feel it's important to distinguish that the OP-s solution loops over the whole array twice. I know there are times to make a trade-off between performance and readability, but I don't feel this needs to be one of those times :)
wow crazy matt
thanks for this
Great answer, thank you Matt!
Here's another possibility using the
Map
class constructor andvalues
method:There is a difference between Tony's and Matt's approach in how the final array will look like.
Matt's approach is adding the id for each entry it loops through to a Set and checks whether or not it has been ´seen´ before or not, and return the object if 'no' is the case. So if we look at the returned object with ID: 2, Matt will return the object with name: "test2" as it will consider the next object a duplicate and skip it.
Tony's approach is by creating a new map using ID as a key - which has to be unique - and then extracts the values. E.g.
[1: { id: 1, name: "test1" }, 2: { id: 2, name: "test2" }....]
etc. What this means though, is that even though id: 2 has been added to the map, it is simply overwritten by the third item in the array, thus Tony will return name: "test3" for ID: 2.Just keep this in mind whether you want the first object or the last object by a duplicated identifier to be the truth.
I have to create an account and say thank you! This answer save my day.
Hi Tony. Your answer helped me, thanks!
BTW, can you please help me achieve this array?
[
{ id: 1, name: "test1" },
{ id: 2, name: "test2" },
{ id: 2, name: "test3" },
{ id: 3, name: "test2" }
]
I mean even if 'id' or 'name' already exists, it should not be omitted because either of the value is different (like in the case of 'name: "test2"') in the whole array.
Hey @mayanxoni ,
Might be late with a reply here, but in your case I would probably map through your array of objects as stringified content, as you are not relying on a single identifier but an entire object.
NB: Though this might not be performant when you are dealing with bigger objects and large arrays.
Hi Mayank,
I'm not sure I follow. If no duplicates are removed then that is just the original array is it not? Or do you mean you want an array with just
id
s 1, 2, and 3? If so, you can use Array.prototype.filter and only returntrue
for theid
s you want to keep.Great
wow, i love that
Thanks !!
Interesting challenge. So I've three very similar solutions. They are all based on the same principle of reducing the array into a key-value structure and re-creating the array from the values only.
Approach 1: Classical Reducer
(reducer maintains immutability)
Depending on your array size, this approach might easily become a bottleneck in your app. More performant is to mutate your accumulator object directly in the reducer.
Approach 2: Reducer with object-mutation
The larger your input array, the more performance gain you'll have from the second approach. In my benchmark (for an input array of length 500 - with a duplicate element probability of 0.5), the second approach is ~440 x as fast as the first approach.
Approach 3: Using ES6 Map
My favorite approach uses a map, instead of an object to accumulate the elements. This has the advantage of preserving the ordering of the original array:
Using the the same benchmark conditions as above, this approach is ~2 x as fast as the second approach and ~900 x as fast as the first approach.
Conclusion
Even if all three approaches are looking quite similar, they have surprisingly different performance footprints.
You'll find the benchmarks I used here: jsperf.com/uniq-by-prop
Hi ! One other one line path to Rome, from France :
`
Merci! :)
More JS but too slow.
I have also this solution O.o
But this only works with
address.id
, so this doesn't work withaddress.name
Really, why this doesn't work like that?
Well, you're passing
[address.id]
as an index to thedupAddress
array, that's just not going to work because theid !== index
. Try changing it toaddress.id
oraddress.name
without accessing the arrayOkay, I tried it didn't work actually I was wonder why that didn't work. Thanks.
let array = [];
let singleEle = [];
const arr = [
{ id: 1, {questionId : { _id: "5e2016a1560d8c2aa842e65d"} }},
{ id: 1, {questionId : { _id: "5e1c211cc201f33834e7baf1"} }},
{ id: 1, {questionId : { _id: "5e201733560d8c2aa842e65e"} }}
];
arr.forEach(item => {
if (array[item.questionId._id] ) {
}
else{
array[item.questionId._id] = true;
singleEle.push(item)
}
});
I found myself with this issue recently and though I've always used the same code to find distinct primitives (before we had the
Set
object), this code required me to adhere to the C# API where you pass in a comparison functionT -> T -> boolean
. This solution felt relatively clean though obviously not in linear time.github.com/jreina/ShittyLINQ.js/bl...
Thanks for chairing, I found this also helpful
Other solutions...
Leave last appearance:
Leave first appearance:
Remove duplicated names also:
Thanks for the code snippet, Marina...I'm getting to errors when I attempt to use it. The first is "Set is only referred to a type but is being used as a value here"
when I use the "REDUCE" example I get the following in the console:
Maximum call stack size exceeded
at Array.reduce
Man, I only created an account here just for saying thanks. So... thanks! :D
I came here because Chat GPT suggested to me a filter-based solution that did not work as filter does consider two objects unequal due to different spots in memory, eventhough they contain the same values.
You saved me a lot of headaches.
I have two list of objects and I need to remove all duplicates, something like this:
INPUTS
var array1 = [(1, 'banana', 'yellow'), (1, 'apple', 'red'), (1, 'orange', 'orange')];
var array2 = [(1, 'banana', 'yellow'), (1, 'apple', 'red'), (2, 'grapes', 'purple')];
OUTPUT
array1 = [(1, 'orange', 'orange')]
I tried using filter but it doesn't work for objects :(
what does this bit do? not sure I understand? -> acc.concat([current])
Array.concat is a way to concatenate two arrays into one.
developer.mozilla.org/en-US/docs/W...
Thanks for the solution.
Thanks for this post
Thank you @marinamosti , you saved my life xD
The array reduce solution saved my day!
Tanx Marina
Welcome! :D
Thanks! This is exactly what I was looking for
Really enjoyed this article and the rad discussion!!!!!!
Thanks so much for your article. It saved and made my day. :)
This is great! Thanks