The Answers:
Answer #1 -- Pretty & Dynamic:
let result = [...new Set(arr.map(item=>item.tag_type))];
Answer #2 -- Fast (5X as fast as the top answer)
let tagTypes = {};
arr.forEach(item => tagTypes[item.tag_type] = true)
let result = Object.keys(tagTypes)
The explanation:
Most of the existing answers are perfectly functional, especially for this small of a data-set. The problems begin to arise when you have thousands of items to iterate over, so let’s talk performance.
Every response thus far has used Array.prototype.indexOf inside some kind of loop. The problem with this is that indexOf itself is a loop.
As a result, @quirimmo’s response iterates 11 times and @SeanGregory’s iterates 10 times.
Below, I will explain how to achieve the desired effect without nesting loops.
Answer #1
Let’s break this apart:
let result = [...new Set(arr.map(item=>item.tag_type))]
In the center of this, we have the map . This should be familiar.
let allTagTypes = arr.map(item=>item.tag_type)
The ES6 Set is an iterable object which, “lets you store unique values of any type, whether primitive values or object references.”
This means when you construct a Set, passing it an array with duplicate items, the resulting Set will essentially remove the duplicates and only store each item once.
As such, we can do the following and get a Set of unique tag types:
let filteredTagTypes = new Set(allTagTypes);
This is great, but we want the results as an Array, not a Set. We can convert this Set into an array using the Spread Operator.
let result = [...filteredTagTypes];
// ["Takmicenje","Fudabal","Tim","Liga","Fudbal"]
That’s it!
Notes: The question was about how to filter out duplicates from an array of property values. This solution will work for all types of values. For the asker’s specific scenario (the values always being strings), Answer #2 is considerably better.
As it turns out, the construction of a Set is a relatively heavy process. Performance-wise, we end up in about the same place as with indexOf. It's a one-liner though, so why not? :)
Now for numero dos!
Answer #2
This one is a bit more succinct.
let tagTypes = {};
arr.forEach(item => tagTypes[item.tag_type] = true)
let result = Object.keys(tagTypes)
First, we create an object that will hold our tag types.
let tagTypes = {};
Next, we loop through each item in the array.
For each item, we set a property on the tagTypes object with a key of the item’s tag_name and a value of true. If the property is already there, it’s simply overwritten with the same thing. If not, it’s added to the object.
When the loop is complete, tagTypes will be an object that looks like this:
{
"Takmicenje":true,
"Fudabal":true,
"Tim":true,
"Liga":true,
"Fudbal":true
}
We can now get an Array of tagTypes' keys using Object.keys().
let result = Object.keys(tagTypes)
// ["Takmicenje","Fudabal","Tim","Liga","Fudbal"]
That’s two iterations. Vroom vroom!
The Results
Here’s a snippet running each function and a JSPerf performance comparison if you’re interested:
JSPerf: https://jsperf.com/unique-array-items-from-properties
let arr = [{"id":1, "image":"sport.jpg", "tag_name":"Sport","tag_type":"Takmicenje","my_feed":true, "my_favourites":true},
{"id":2, "image":"sport.jpg", "tag_name":"Fudbal","tag_type":"Takmicenje","my_feed":true, "my_favourites":true},
{"id":3, "image":"sport.jpg","tag_name":"Premier League","tag_type":"Takmicenje","my_feed":false,"my_favourites":true},
{"id":4, "image":"sport.jpg", "tag_name":"La liga","tag_type":"Takmicenje","my_feed":true,"my_favourites":true},
{"id":5, "image":"sport.jpg", "tag_name":"Real Madrid","tag_type":"Fudabal","my_feed":true,"my_favourites":true},
{"id":6, "image":"sport.jpg","tag_name":"UEFA","tag_type":"Tim","my_feed":true,"my_favourites":true},
{"id":7,"image":"sport.jpg","tag_name":"Juve","tag_type":"Liga","my_feed":true,"my_favourites":false},
{"id":8,"image":"sport.jpg","tag_name":"Barca","tag_type":"Takmicenje","my_feed":false,"my_favourites":true},
{"id":9,"image":"sport.jpg","tag_name":"Sport","tag_type":"Fudbal","my_feed":true,"my_favourites":true}
];
function withSet(arr){ // Answer #1
return [...new Set(arr.map(item=>item.tag_type))]
}
function withObject(arr){ // Answer #2
let tagTypes = {};
arr.forEach(item => tagTypes[item.tag_type] = true)
return Object.keys(tagTypes)
}
console.log('With Object', withObject(arr))
console.log('With Set', withSet(arr))
Note: in the question, it says the desired result is ['Takmicenje','Fudbal','Tim','Liga'], but the actual result with duplicates removed is [“Takmicenje", "Fudabal", "Tim", "Liga", "Fudbal"].
filt.indexOf(filt)doesn't make a lot of sense in that context