Reputation: 2371
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?
Upvotes: 3
Views: 20682
Reputation: 26161
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);
Upvotes: 1
Reputation: 9
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));
Upvotes: -1
Reputation: 275
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:
https://jsbin.com/yesucaquwa/1/edit?js,console
Upvotes: 1
Reputation: 386550
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);
Upvotes: 3
Reputation: 66478
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);
Upvotes: 0