Hi I am calling an API where it returns an Object containing questions and answers like so
{
"questions":[
{
"id":1,
"questionHeader":"Some question header",
"questionText":"Some question text?",
},
{
"id":2,
"questionHeader":"Some question header",
"questionText":"Some question text?",
},
],
"answers":[
{
"id":1,
"questionId":1,
"answer":"Some answer",
},
{
"id":2,
"questionId":1,
"answer":"Some answer",
},
{
"id":3,
"questionId":2,
"answer":"Some answer",
},
]
}
What I am trying to achieve is to get the answers embedded within their respective question based on a questions id and an answers questionId. So for the above, I am trying to achieve something like the following.
{
"questions":[
{
"id":1,
"questionHeader":"Some question header",
"questionText":"Some question text?",
"answers":[
{
"id":1,
"questionId":1,
"answer":"Some answer",
},
{
"id":2,
"questionId":1,
"answer":"Some answer",
},
]
},
{
"id":2,
"questionHeader":"Some question header",
"questionText":"Some question text?",
"answers":[
{
"id":3,
"questionId":2,
"answer":"Some answer",
},
]
},
],
}
I have something which adds some answers but not as an array of objects per question. Currently I have this
const newItem = data.questions.map((t1) => ({
...t1,
...data.answers.find((t2) => t2.questionId === t1.id),
}));
console.log(newItem);
I have set up a JSFiddle. How can I achieve my desired output?
Thanks
CodePudding user response:
Index the questions by ID first, then iterate over the answers. The question ID will make it easy to access the associated question - just use bracket notation to look it up on the indexed object, and you can push to that question's answers. After iteration is finished, turn the questions back into an array again.
const data={questions:[{id:1,questionHeader:"Some question header",questionText:"Some question text?"},{id:2,questionHeader:"Some question header",questionText:"Some question text?"}],answers:[{id:1,questionId:1,answer:"Some answer"},{id:2,questionId:1,answer:"Some answer"},{id:3,questionId:2,answer:"Some answer"}]};
const questionsById = Object.fromEntries(
data.questions.map(question => [question.id, { ...question, answers: [] }])
);
for (const answer of data.answers) {
questionsById[answer.questionId].answers.push(answer);
}
const output = Object.values(questionsById);
console.log(output);
The above is O(n)
because there are no nested loops. If you wanted to tweak your nested loop approach (O(n ^ 2)
) so that it works. .filter
instead of .find
so you can get an array of answers, and prefix the property in the object there with answers:
instead of spreading.
const data={questions:[{id:1,questionHeader:"Some question header",questionText:"Some question text?"},{id:2,questionHeader:"Some question header",questionText:"Some question text?"}],answers:[{id:1,questionId:1,answer:"Some answer"},{id:2,questionId:1,answer:"Some answer"},{id:3,questionId:2,answer:"Some answer"}]};
const newItem = data.questions.map((t1) => ({
...t1,
answers: data.answers.filter((t2) => t2.questionId === t1.id),
}));
console.log(newItem);
CodePudding user response:
Array#filter
can be used to find all the answers with a specific question id. (Note that Array#find
only returns the first element matching a condition.)
const data={questions:[{id:1,questionHeader:"Some question header",questionText:"Some question text?"},{id:2,questionHeader:"Some question header",questionText:"Some question text?"},],answers:[{id:1,questionId:1,answer:"Some answer"},{id:2,questionId:1,answer:"Some answer"},{id:3,questionId:2,answer:"Some answer"},]};
const newItem = data.questions.map((t1) => ({
...t1,
answers: data.answers.filter((t2) => t2.questionId === t1.id),
}));
console.log(newItem);
CodePudding user response:
This is my take... simple forEach
var response = {
"questions": [{
"id": 1,
"questionHeader": "Some question header",
"questionText": "Some question text?",
},
{
"id": 2,
"questionHeader": "Some question header",
"questionText": "Some question text?",
},
],
"answers": [{
"id": 1,
"questionId": 1,
"answer": "Some answer",
},
{
"id": 2,
"questionId": 1,
"answer": "Some answer",
},
{
"id": 3,
"questionId": 2,
"answer": "Some answer",
},
]
}
response.answers.forEach(function(answer) {
var question = response.questions.find(function(item) {
return (item.id == answer.questionId)
})
question.answers = (question.answers || [])
question.answers.push(answer)
})
delete response.answers;
console.log(response)