How can I turn this array of objects (which has some duplicate objects):
items =
[
{ TYPEID: 150927, NAME: 'Staples', COLOR: 'Silver' },
{ TYPEID: 1246007, NAME: 'Pencils', COLOR: 'Yellow' },
{ TYPEID: 1246007, NAME: 'Pencils', COLOR: 'Blue' },
{ TYPEID: 150927, NAME: 'Staples', COLOR: 'Black' },
{ TYPEID: 1248350, NAME: 'Staples', COLOR: 'Black' },
{ TYPEID: 1246007, NAME: 'Pencils', COLOR: 'Blue' },
{ TYPEID: 150927, NAME: 'Staples', COLOR: 'Silver' },
{ TYPEID: 150927, NAME: 'Fasteners', COLOR: 'Silver' }
]
Into this:
items =
[
{ TYPEID: 150927, NAME: 'Staples', COLOR: 'Silver' },
{ TYPEID: 1246007, NAME: 'Pencils', COLOR: 'Yellow' },
{ TYPEID: 1246007, NAME: 'Pencils', COLOR: 'Blue' },
{ TYPEID: 150927, NAME: 'Staples', COLOR: 'Black' },
{ TYPEID: 1248350, NAME: 'Staples', COLOR: 'Black' },
{ TYPEID: 150927, NAME: 'Fasteners', COLOR: 'Silver' }
]
...by filtering out the two duplicate objects (the silver staples and the blue pencils)?
It seems like there should be an easy way to do this, but I've yet to find a simple solution.
I've seen some javascript / jquery code which does this, but I'm not the best at converting those into coffeescript.
UPDATE:
There will often be different objects with the very similar properties.
In the actual application, each object has a potential of 25 properties.
I only want to remove objects if each of those properties are equal.
UPDATE 2
This is the code that ended up working for me - (thanks to rjz)
unique = (objAry, callback) ->
results = []
valMatch = (seen, obj) ->
for other in seen
match = true
for key, val of obj
match = false unless other[key] == val
return true if match
false
objAry.forEach (item) ->
unless valMatch(results, item)
results.push(item)
callback null, results
And this is how I'll call it:
unique items, (err, items) ->
console.log items
Depending how deeply you want to check equality, you could probably just assume uniqueness of the USERID field and do something like this:
ids = [] # Contains list of "seen" IDs
result = [] # Contains list of unique users
users.forEach (u) ->
if result.indexOf(u.USERID) == -1
result.push(u)
ids.push(u.USERID)
If you need to do deeper matching and don't have a primary key available (might be a sign of bigger issues), you could create a more sophisticated test for equality:
valMatch = (seen, obj) ->
for other in seen
match = true
for key, val of obj
match = false unless other[key] == val
return true if match
false
result = []
seen = []
data.forEach (datum) ->
unless valMatch(result, datum)
result.push(datum)
seen.push(datum)
I would use underscore.js and try something like this
result = item[0] for item in _.groupBy(users, (user) => user.USERID)
Its not tested thou ;-) obviously this assumes that we only check for the USERID
if you can't only check for the USERID you could of course transform all objects into json-strings and then compare the json strings
result = item[0] for item in _.groupBy(users, (user) => user.toJSON())
obviously this is a dirty hack that will rely on the fact that all browsers and engines serialize objects and their slots in the order of creation/assignment.
So in any way rjz's solution is certainly the better one but this will most likely work as well.