Home > Enterprise >  Matching nested objects with another array of objects and counting
Matching nested objects with another array of objects and counting

Time:09-01

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)

  • Related