user11429164
user11429164

Reputation: 87

How to create a tree with a condition in javascript?

Good morning, I would like to implement an algorithm that generates a node at each loop. If the node satisfies the condition, then it adds a child to it which contains a node with children if it satisfies the condition, etc.

I have an entry like below :

  {
    id: 1,
    entitled: "first question",
    questions: [
      {
        id: 1,
        entitled: "Do you have a car ?",
        answers: [
          { id: 1, entitled: "Yes", conditionalSection: 2 },
          { id: 2, entitled: "No", conditionalSection: 3 },
        ],
      },
    ],
  },
  {
    id: 2,
    entitled: "section yes",
    questions: [
      {
        id: 1,
        entitled: "Do you have an electric car ?",
        answers: [
          { id: 1, entitled: "Yes", conditionalSection: 4 },
          { id: 2, entitled: "No", conditionalSection: 4 },
        ],
      },
    ],
  },
  {
    id: 3,
    entitled: "section no",
    questions: [
      {
        id: 1,
        entitled: "Do you have a bicycle ?",
        answers: [
          { id: 1, entitled: "Yes", conditionalSection: 4 },
          { id: 2, entitled: "No", conditionalSection: 4 },
        ],
      }
    ],
  },
  {
    id: 4,
    entitled: "end",
    questions: [
      {
        id: 1,
        entitled: "Do you have any comments ?",
      }
    ],
  },
];

and the output :

{
  name: "Do you have a car ?",
  children: [
    {
      name: "Yes",
      children: [
        {
          name: "Do you have an electric car ?",
          children: [
            { name: "Yes", children: [{ name: "Do you have any comments ?" }] },
            { name: "No", children: [{ name: "Do you have any comments ?" }] },
          ],
        },
      ],
    },
    {
      name: "No",
      children: [
        {
          name: "Do you have a bicycle ?",
          children: [
            { name: "Yes", children: [{ name: "Do you have any comments ?" }] },
            { name: "No", children: [{ name: "Do you have any comments ?" }] },
          ],
        },
      ],
    },
  ],
};

I tried to do something like this (but i'm lost) :

const output = []
const prototype = { name: "", children: [] };
sections.forEach((section, index) => {
    prototype[index] = prototype;
});
sections.forEach((section, index) => {
  let next = prototype;
  section.questions.forEach((question, index) => {
    let now = next;
    next = prototype;
    question.answers((answer, index) => {
        if (answer.conditionalSection!==null){
            output.push(next)
        }
    });
  });
});

Upvotes: 0

Views: 464

Answers (1)

Nina Scholz
Nina Scholz

Reputation: 386868

You could take some functions for getting questions and answers for a nested result.

This approach uses an object as reference to the objects of the first level and omits children.

var data = [{ id: 1, entitled: "first question", questions: [{ id: 1, entitled: "Do you have a car ?", answers: [{ id: 1, entitled: "Yes", conditionalSection: 2 }, { id: 2, entitled: "No", conditionalSection: 3 }] }] }, { id: 2, entitled: "section yes", questions: [{ id: 1, entitled: "Do you have an electric car ?", answers: [{ id: 1, entitled: "Yes", conditionalSection: 4 }, { id: 2, entitled: "No", conditionalSection: 4 }] }] }, { id: 3, entitled: "section no", questions: [{ id: 1, entitled: "Do you have a bicycle ?", answers: [{ id: 1, entitled: "Yes", conditionalSection: 4 }, { id: 2, entitled: "No", conditionalSection: 4 }] }] }, { id: 4, entitled: "end", questions: [{ id: 1, entitled: "Do you have any comments ?" }] }],
    children = {},
    references = data.reduce((r, o) => {
        r[o.id] = o;
        o.questions.forEach(({ answers = [] }) => answers.forEach(o => {
            if ('conditionalSection' in o) children[o.conditionalSection] = true;
        }));
        return r;
    }, {}),
    getReference = k => (references[k].questions || []).map(mapQuestions),
    mapQuestions = ({ entitled: name, answers }) =>
        ({ name, ...(answers && { children: answers.map(mapAnswers) }) }),
    mapAnswers = ({ entitled: name, conditionalSection: k }) =>
        ({ name, ...(k in references && { children: getReference(k) }) }),
    result = Object.keys(references)
        .filter(k => !(k in children))
        .flatMap(getReference);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Related Questions