Javascript get unique value of an indented json

Viewed 64

I have JSON array of objects with the following structure:

obj: [
    {   
        itemTitle: 'title-a',
        itemTags: [
            { tag: 'tag-a' },
            { tag: 'tag-b' }
        ]                       
    },
    {   
        itemTitle: 'title-b',
        itemTags: [
            { tag: 'tag-c' }
        ]                       
    },
    {   
        itemTitle: 'title-c',
        itemTags: [
            { tag: 'tag-c' },
            { tag: 'tag-b' }
        ]                       
    }
]

I need to extract distinct tags value in an array like this [tag-a, tag-b, tag-c] I'll try this approach:

const tagsArray = obj.map(elem => elem.itemTags);

var tags = [];
for (var i = 0; i < tagsArray.length; i++) {
    tags.push(tagsArray[i].map(item => item.tag))
}
//tagsArray[0]: [{"tag":"tag-a"},{"tag":"tag-b"}]
//tagsArray[1]: [{"tag":"tag-c"}]
//tagsArray[2]: [{"tag":"tag-c"},{"tag":"tag-b"}]

//tags: tag-a,tag-b,tag-c,tag-c,tag-b

const unique = [...new Set(tags)];
//unique: tag-a,tag-b,tag-c,tag-c,tag-b

it does not return distinct values

3 Answers

Problem

You are pushing the array into each item in tagsArray. The content looks like

[["tag-a","tag-b"],["tag-c"],["tag-c","tag-b"]]

While you need

["tag-a","tag-b","tag-c","tag-c","tag-b"]

Solution

==> Using concat instead of push

const obj = [{itemTitle:'title-a',itemTags:[{tag:'tag-a'},{tag:'tag-b'}]},{itemTitle:'title-b',itemTags:[{tag:'tag-c'}]},{itemTitle:'title-c',itemTags:[{tag:'tag-c'},{tag:'tag-b'}]}];

var tags = [];
const tagsArray = obj.map(elem => elem.itemTags);
for (var i = 0; i < tagsArray.length; i++)
    tags = tags.concat(tagsArray[i].map(item => item.tag)); // Use concat instead of push
const unique = [...new Set(tags)];
console.log(unique);

Refactor code

You can use Array#flatMap

const obj = [{itemTitle:'title-a',itemTags:[{tag:'tag-a'},{tag:'tag-b'}]},{itemTitle:'title-b',itemTags:[{tag:'tag-c'}]},{itemTitle:'title-c',itemTags:[{tag:'tag-c'},{tag:'tag-b'}]}];

const tagsArray = obj.flatMap(({itemTags}) => itemTags.map(({tag}) => tag));
console.log([...new Set(tagsArray )]);

The flatMap() method returns a new array formed by applying a given callback function to each element of the array, and then flattening the result by one level


You can try getting the tag in the same loop with flatMap() and map()

var obj = [
    {   
        itemTitle: 'title-a',
        itemTags: [
            { tag: 'tag-a' },
            { tag: 'tag-b' }
        ]                       
    },
    {   
        itemTitle: 'title-b',
        itemTags: [
            { tag: 'tag-c' }
        ]                       
    },
    {   
        itemTitle: 'title-c',
        itemTags: [
            { tag: 'tag-c' },
            { tag: 'tag-b' }
        ]                       
    }
]
const tagsArray = obj.flatMap(elem => elem.itemTags.map(i=>i.tag));

const unique = [...new Set(tagsArray)];
console.log(unique)

let t=arr.flatMap(item=>item.itemTags.flatMap(tag=>Object.values(tag)))
u = new Set([...t])

Related