riddickulous riddickulous - 6 months ago 8
Javascript Question

Javascript - How to transform array list into another array list of key values?

So I've been stumped on this for hours and I can't really figure out an elegant solution to solve this problem. Let's say I have an array like this:

[
{
question: "what is your name?",
answer: "Ben",
topic: "names"
},
{
question: "what is your name?",
answer: "Ben",
topic: "names"
},
{
question: "What is dog's name?",
answer: "Snugglets",
topic: "names"
},
{
question: "What is your brother's age?",
answer: 55,
topic: "ages"
}
]


How can I turn this into an array that looks like this?

[
{
topic: "names",
content: [...array of objects based on "names"...]
},
{
topic: "ages",
content: [...array of objects based on "ages"...]
}
]


I feel this is something that should be really easy, but for some reason my brain cannot seem to grasp the solution. What am I missing here?

UPDATE: Thanks for all the responses! I was not expecting to get this many methods of accomplishing this. I accepted one of the answers, as it was related to ES6 and I should have specified that I was looking to learn the ES6 way of doing this, if possible :)

Though, I must also say that the needs have also changed a bit where instead of the intended array, being like this:

[
{
topic: "names",
content: [...array of objects based on "names"...]
},
{
topic: "ages",
content: [...array of objects based on "ages"...]
}
]


The array needs to look like more like this:

[
{
topic: "names",
content: '<div>
<h3>Question: What is your name?</h3>
<p>Answer: Ben</p>
</div>
<div>
<h3>Question: What is your dog's name?</h3>
<p>Answer: Snugglets</p>
</div>'
},
{
topic: "ages",
content: content: '<div>
<h3>Question: What is your age?</h3>
<p>Answer: 50</p>
</div>
<div>
<h3>Question: What is your brother's age?</h3>
<p>Answer: 52</p>
</div>'
}
]


Normally I don't like to just ask for code given to me, but my Javascript foo seems to a bit weaker when it comes to transforming data algorithmically :( Any thoughts on how I could merge all of those array elements into a single string, containing HTML, that serves as the "content" key of each "topic"?

Also, would this be better served in another question on Stackoverflow?

Answer

Can be simply done as follows when ES6 Map object is utilized. I also removed the redundant names property from the items of the content array.

var data = [{question: "what is your name?",answer: "Ben",topic: "names"},{question: "what is your name?",answer: "Ben",topic: "names"},{question: "What is dog's name?",answer: "Snugglets",topic: "names"},{question: "What is your brother's age?",answer: 55,topic: "ages"}],
 mapData = data.reduce((p,c) => p.has(c.topic) ? p.set(c.topic,p.get(c.topic).concat({question:c.question,
                                                                                        answer:c.answer}))
                                               : p.set(c.topic,[{question:c.question,
                                                                   answer:c.answer}]),new Map()),
  result = [...mapData].map(e => ({topic:e[0],content:e[1]}));
console.log(result);