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?
5 Answers
You could group it with a temporary object and iterate over with Array#forEach.
The
forEach()method executes a provided function once per array element.
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" }], group = []; data.forEach(function (a) { if (!this[a.topic]) { this[a.topic] = { topic: a.topic, content: [] }; group.push(this[a.topic]); } this[a.topic].content.push(a); }, Object.create(null)); console.log(group);1Can 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);A more functional approach is to use Array.reduce. This also removes the need for a temporary variable:
var output = data.reduce(function(prev, cur) { if (!prev[cur.topic]) prev[cur.topic] = []; prev[cur.topic].push(cur); return prev; }, {}); See JS Bin for working example:
Try this:
var input = [ { 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" } ]; var tmp = input.reduce(function(topics, obj) { topics[obj.topic] = topics[obj.topic] || {topic: obj.topic, content: []}; topics[obj.topic].content.push(obj); return topics; }, {}); var output = Object.keys(tmp).map(function(key) { return tmp[key]; }); console.log(output);There is a simple function for you.
var arr=[ { 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" } ] function turnToOtherArray(arr){ var result=[]; for(var i=0,mamorize={};i<arr.length;i++){ if(mamorize[arr[i].topic]){ mamorize[arr[i].topic].push(arr[i].question) }else{ mamorize[arr[i].topic]=[arr[i].question] } } for(var key in mamorize){ result[result.length] = { "topic" : key , "content" : mamorize[key]} } return result; } console.log(turnToOtherArray(arr));