I have a questions object with nested objects:
const questions = {
QID5: {
choices: {
1: { choiceText: "Label 1" },
2: { choiceText: "Label 2" },
3: { choiceText: "Label 3" }
}
},
QID6: {
choices: {
1: { choiceText: "English" },
2: { choiceText: "French" }
}
}
};
And an array of responses:
const responses = [
{
labels: {
QID5: ["Label 1", "Label 3"],
QID6: ["English", "French"]
}
},
{
labels: {
QID5: ["Label 1"],
QID6: ["English"]
}
},
{
labels: {
QID5: ["Label 2", "Label 3"],
QID6: ["English"]
}
}
];
I want to count the occurrence of each choice in questions
in each of the responses for a particular question (QID) and put them in arrays as a property (x, y) of a new object
For example the desired result for QID5 should be:
const desiredResult = {
id: "QID5",
x: ["Label 1", "Label 2", "Label 3"],
y: [2, 1, 2]
};
Label 1 in desiredResult.x
gets the value 2 in desiredResult.y
(because it appears in two of the responses) and so on...
How can I achieve this result?
Here is what I've tried:
function getResults(id) {
return responses.flatMap(response => response.labels[id])
}
const arr = getResults("QID5");
const counts = {};
arr.forEach((x) => {
counts[x] = (counts[x] || 0) 1;
});
const x = Object.keys(counts)
const y = Object.values(counts)
console.log(x)
console.log(y)
CodePudding user response:
You can get the x
values by mapping the question choices
into the choiceText
values. You can then get each y
value by iterating the x
values, counting whether the value occurs in the labels for the question id
in each response:
const questions = {
QID5: {
choices: {
1: { choiceText: "Label 1" },
2: { choiceText: "Label 2" },
3: { choiceText: "Label 3" }
}
},
QID6: {
choices: {
1: { choiceText: "English" },
2: { choiceText: "French" }
}
}
};
const responses = [
{
labels: {
QID5: ["Label 1", "Label 3"],
QID6: ["English", "French"]
}
},
{
labels: {
// QID5: ["Label 1"],
QID6: ["English"]
}
},
{
labels: {
QID5: ["Label 2", "Label 3"],
QID6: ["English"]
}
}
];
const getResults = (id) => {
const x = Object.values(questions[id].choices).map(({ choiceText }) => choiceText);
const y = x.map(l => responses.reduce((acc, r) => acc (r.labels[id]?.includes(l) || 0), 0))
return { id, x, y }
}
console.log(getResults('QID5'))
CodePudding user response:
Here's a simpler solution if you have to sort the labels by label number:
const responses = [
{
labels: {
QID5: ["Label 1", "Label 3"],
QID6: ["English", "French"]
}
},
{
labels: {
QID5: ["Label 1"],
QID6: ["English"]
}
},
{
labels: {
QID5: ["Label 2", "Label 3"],
QID6: ["English"]
}
}
];
function getResults(id) {
return responses.flatMap(response => response.labels[id])
}
const arr = getResults("QID5");
const counts = {};
arr.forEach((x) => {
counts[x] = (counts[x] || 0) 1;
});
// sort the kays by the lable number, which is the 6th character in the key (would vary if the key is changed)
const x = Object.keys(counts).sort((key, nextKey) => parseInt(key[6], 10) - parseInt(nextKey[6], 10));
const y = x.map(key => counts[key]) // get each key's corresponding number
const desiredObject = {
id: "QID5", // or an variable / function arg
x,
y
}
console.log(desiredObject)