nick
nick

Reputation: 83

Nesting a Nested Object with Reduce

I have an array of objects which I want to turn into an object using Reduce:

const results = [{
    person: "person1",
    choice: 0,
    questionId: "a"
  },
  {
    person: "person1",
    choice: 1,
    questionId: "b"
  },
  {
    ...
  }
];

and want to return an object with this expected output:

    {
      results: [
        person1: {
          a: [1, 0, 0, 0],
          b: [0, 1, 0, 0],
          c: [0, 0, 0, 0]
        },
        person2: {
          a: [0, 0, 0, 0],
          b: [0, 0, 1, 0],
          c: [0, 1, 0, 0]
        },
        person3: {
          a: [0, 0, 0, 1],
          b: [0, 0, 0, 0],
          c: [0, 0, 0, 0]
        }
      ]
    }

Where each a: [...] refers to a count of "choice" [0,1,2,3] for each "question" [a,b,c]. The Person should be the index, and the questionId might be variable (it may include "d" for example").

My attempt:

        const results = [{
person: "person1",
choice: 0,
questionId: "a"
  },
  {
person: "person1",
choice: 1,
questionId: "b"
  },
  {
person: "person2",
choice: 2,
questionId: "c"
  },
  {
person: "person2",
choice: 3,
questionId: "b"
  },
  {
person: "person3",
choice: 2,
questionId: "a"
  }
]; 

people = ["person1", "person2", "person3"];

let responses = results.reduce((init, response) => {
      switch (response.segment) {
        case people[0]:
          init[people[0]][response.questionId].push(response.choice[0])
          break;
        case people[1]:
          init[people[1]][response.questionId].push(response.choice[0])
          break;
          case people[2]:
          init[people[2]][response.questionId].push(response.choice[0]);
          break;
            default:
            	break;
          }
		return init;
      });
      
console.log(responses);

I'm unsure how to initiate the object to allow for appending the questions and getting the format I require?

Thanks very much.

Upvotes: 1

Views: 836

Answers (1)

mhodges
mhodges

Reputation: 11116

Assuming in your output you meant { "person1": {...}, ...} instead of [ "person1": {...}, ...] (as the latter is a syntax error), you can do it using reduce, like this:

const results = [
  { person: "person1", choice: 0, questionId: "a" },
  { person: "person1", choice: 1, questionId: "b" },
  { person: "person2", choice: 2, questionId: "c" },
  { person: "person2", choice: 3, questionId: "b" },
  { person: "person3", choice: 2, questionId: "a" }
]; 

// create an array of all unique questionIds found in the results array
var questionIds = Array.from(new Set(results.map(result => result.questionId)));
console.log(questionIds);

var resultsObj = {
  results: results.reduce((res, {person, questionId, choice}) => {
    // if person hasn't been created yet, create them
    if (!res[person]) {
      // need to do .map here instead of outside so we get fresh array references for each person
      res[person] = Object.assign({}, ...questionIds.map(id => ({[id]: [0,0,0,0]})));
    }
    // log a 1 in the correct slot for the answer given
    res[person][questionId][choice] = 1;
    return res;
  }, {})
};

console.log(resultsObj);

Upvotes: 1

Related Questions