0

Can we achieve a group by on an array of objects by object's key where key is also an array?

[
    {
        "name": "Apple",
        "tags": ["fruits"]
    },
    {
        "name": "Orange",
        "tags": ["fruits"]
    },
    {
        "name": "Tomato",
        "tags": ["fruits", "vegetables"]
    }
]

Wanted results in an object after the group by:

{
    "fruits": [
        {
            "name": "Apple",
            "tags": ["fruits"]
        },
        {
            "name": "Orange",
            "tags": ["fruits"]
        },
        {
            "name": "Tomato",
            "tags": ["fruits", "vegetables"]
        }
    ],
    "vegetables": [
        {
            "name": "Tomato",
            "tags": ["fruits", "vegetables"]
        }
    ]
}

Vanilla or Lodash solution is very welcome!

Edit

Thanks everyone, here is what I ended up using:

const groupBy = key => array =>
    array.reduce((obj, el) => {
        el[key].forEach(k => {
            obj[k] = obj[k] || []
            obj[k].push({ ...el })
        })
        return obj
    }, {})

const groupBySomething = groupBy(`something`)
const grouped = groupBySomething(data)
2
  • Have you tried anything ? Commented Nov 19, 2020 at 11:43
  • @GabrielePetrioli I tried with Lodash's _.groupBy couldn't get it working. Commented Nov 19, 2020 at 11:45

3 Answers 3

3

This uses Array.prototype.reduce and Array.prototype.forEach

{
  const data = [
    {
        "name": "Apple",
        "tags": ["fruits"]
    },
    {
        "name": "Orange",
        "tags": ["fruits"]
    },
    {
        "name": "Tomato",
        "tags": ["fruits", "vegetables"]
    }
  ]
 
  const groupedData = data.reduce((carry, element) => {
    element.tags.forEach(tag => {
      carry[tag] = carry[tag] || []
      carry[tag].push({...element})
    })
    return carry; 
  }, {})
  
  console.log(groupedData)
}

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

Comments

3

Here:

let arr = [
    {
        "name": "Apple",
        "tags": ["fruits"]
    },
    {
        "name": "Orange",
        "tags": ["fruits"]
    },
    {
        "name": "Tomato",
        "tags": ["fruits", "vegetables"]
    }
];

let response = {};
for(let i of arr){
  for(let j of i.tags){
     let tags =[...i.tags]
     if(response[j]){
        response[j].push({...i , tags: tags})
     } else{
        response[j] = [{...i, tags: tags}];
     }
  }
}

console.log(response)

Comments

1

A slightly more terse version of @yunzen version.

input data:

const data = [
    {
        "name": "Apple",
        "tags": ["fruits"]
    },
    {
        "name": "Orange",
        "tags": ["fruits"]
    },
    {
        "name": "Tomato",
        "tags": ["fruits", "vegetables"]
    }
];
const convertData = data.reduce((target, currentElem) => {
        currentElem.tags.forEach(tag => {
            target[tag] ? target[tag].push({...currentElem}) : target[tag] = [{...currentElem}];
        });
        return target;
}, {});

console.log(convertData);

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.