【问题标题】:Get possible question answer paths (JavaScript)获取可能的问题答案路径 (JavaScript)
【发布时间】:2021-06-19 01:38:33
【问题描述】:

我正在寻找基于问题选项的所有可能的问题答案路径,我整天绞尽脑汁,似乎无法弄清楚为什么我的代码不起作用。

测试代码:

const originalQuestions = {
    1: {
        title: "Title",
        firstQuestion: true,
        options: [{
            tooltip: "",
            nextQuestion: 2
        }, {
            tooltip: "",
            nextQuestion: 2
        }, {
            tooltip: "",
            nextQuestion: 10000
        }]
    },
    2: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 3
        }, {
            tooltip: "",
            nextQuestion: 3
        }, {
            tooltip: "",
            nextQuestion: 3
        }, {
            tooltip: "",
            nextQuestion: 3
        }]
    },
    3: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 4
        }, {
            tooltip: "",
            nextQuestion: 4
        }, {
            tooltip: "",
            nextQuestion: 4
        }]
    },
    4: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 13
        }, {
            tooltip: "",
            nextQuestion: 5
        }]
    },
    5: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 6
        }, {
            tooltip: "",
            nextQuestion: 6
        }, {
            tooltip: "",
            nextQuestion: 6
        }, {
            tooltip: "",
            nextQuestion: 10000
        }]
    },
    6: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 7
        }, {
            tooltip: "",
            nextQuestion: 7
        }, {
            tooltip: "",
            nextQuestion: 7
        }, {
            tooltip: "",
            nextQuestion: 7
        }, {
            tooltip: "",
            nextQuestion: 14
        }]
    },
    7: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 17
        }, {
            tooltip: "",
            nextQuestion: 17
        }, {
            tooltip: "",
            nextQuestion: 17
        }, {
            tooltip: "",
            nextQuestion: 17
        }, {
            tooltip: "",
            nextQuestion: 17
        }]
    },
    8: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 9
        }, {
            tooltip: "",
            nextQuestion: 9
        }, {
            tooltip: "",
            nextQuestion: 9
        }]
    },
    9: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 10
        }, {
            tooltip: "",
            nextQuestion: 10
        }, {
            tooltip: "",
            nextQuestion: 10
        }]
    },
    10: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 11
        }, {
            value: "Roof",
            attribute: "Flue Exit",
            tooltip: "",
            nextQuestion: 15
        }]
    },
    11: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 12
        }, {
            tooltip: "",
            nextQuestion: 12
        }]
    },
    12: {
        finalQuestion: true,
        input: true,
        placeHolder: 'e.g SWS'
    },
    13: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 6
        }, {
            tooltip: "",
            nextQuestion: 6
        }]
    },
    14: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 7
        }, {
            tooltip: "",
            nextQuestion: 7
        }, {
            tooltip: "",
            nextQuestion: 10000
        }]
    },
    15: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 12
        }, {
            tooltip: "",
            nextQuestion: 12
        }]
    },
    17: {
        title: "Title",
        options: [{
            tooltip: "",
            nextQuestion: 8
        }, {
            tooltip: "",
            nextQuestion: 8
        }, {
            tooltip: "",
            nextQuestion: 8
        }, {
            tooltip: "",
            nextQuestion: 8
        }, {
            tooltip: "",
            nextQuestion: 8
        }]
    },
    // Errors
    10000: {
        isError: true,
        title: "Finally, what is the first part of your postcode?",
        error: "Postcode"
    }
};

function loopPaths(currentArrayPath, questionNum, currentQuestion, paths) {

    if (questionNum > 5) {
   return false;
  }

    if (typeof currentQuestion.finalQuestion != 'undefined') {
    return false;
  } else {
    const question = currentQuestion.options;  
    const validPaths = question.filter((e) => e.nextQuestion !== 10000);   
    const clonedPath = [...paths[currentArrayPath][0]];
            
    for (var i = 0; i < validPaths.length; i++) {
      const e = validPaths[i];
            
      if (typeof paths[currentArrayPath][i] == 'undefined') {
        paths[currentArrayPath][i] = [...clonedPath];
      }
      
      paths[currentArrayPath][i].push(questionNum);
      
      loopPaths(currentArrayPath, e.nextQuestion, originalQuestions[e.nextQuestion], paths);
    }
  }
}

function possiblePaths() {
    const question1 = originalQuestions[1].options;
    const validPaths = question1.filter((e) => e.nextQuestion !== 10000);
  
  let paths = [];
  
  /*validPaths.forEach((e, i) => {
    paths[i] = [[1]];
  });*/
      
  /* 
  for (var i = 0; i < validPaths.length; i++) {
    const e = validPaths[i];
           
    loopPaths(e.nextQuestion, boilerQuestions[e.nextQuestion], paths);
  }   */
  
  // Testing with first question, first option
  paths[0] = [[1]];
  loopPaths(0, 2, originalQuestions[2], paths);
  
  console.log(paths);
}

possiblePaths();

似乎发生了什么:(它没有构建正确的路径,也没有构建不同的可能性)

[
  [
    [
      1,
      2,
      3,
      4,
      5,
      4,
      5,
      4,
      5,
      3,
      4,
      5,
      4,
      5,
      4,
      5,
      3,
      4,
      5,
      4,
      5,
      4,
      5,
      3,
      4,
      5,
      4,
      5,
      4,
      5
    ],
    [
      1,
      2,
      3,
      4,
      5,
      3,
      4,
      5,
      4,
      5,
      2,
      4,
      5,
      3,
      4,
      5,
      4,
      5,
      4,
      5,
      3,
      4,
      5,
      4,
      5,
      4,
      5,
      3,
      4,
      5,
      4,
      5
    ]
  ]
]

它应该显示的示例:(我想知道是否有更简单的方法来构建从 1 -> 到最终问题 12 的不同可能性)

[
  [
    [
      1,
      2,
      3,
      4,
      13,
      7,
      17,
      8,
      9,
      10,
      11,
      12
    ],
    [
      1,
      2,
      3,
      4,
      5,
      6,
      7,
      ....
    ]
  ]
]

工作原理:

用户点击问题 1 -> 按下选项 1 -> 用户点击问题 2 -> 按下选项 2 -> 用户点击问题 3 -> 按下选项 1 -> 用户点击问题 4 -> 按下选项 1 -> 用户点击问题13

【问题讨论】:

    标签: javascript arrays


    【解决方案1】:

    您可以使用递归生成器函数。

    const originalQuestions = { 1: { title: "Title", firstQuestion: true, options: [{ tooltip: "", nextQuestion: 2 }, { tooltip: "", nextQuestion: 2 }, { tooltip: "", nextQuestion: 10000 }] }, 2: { title: "Title", options: [{ tooltip: "", nextQuestion: 3 }, { tooltip: "", nextQuestion: 3 }, { tooltip: "", nextQuestion: 3 }, { tooltip: "", nextQuestion: 3 }] }, 3: { title: "Title", options: [{ tooltip: "", nextQuestion: 4 }, { tooltip: "", nextQuestion: 4 }, { tooltip: "", nextQuestion: 4 }] }, 4: { title: "Title", options: [{ tooltip: "", nextQuestion: 13 }, { tooltip: "", nextQuestion: 5 }] }, 5: { title: "Title", options: [{ tooltip: "", nextQuestion: 6 }, { tooltip: "", nextQuestion: 6 }, { tooltip: "", nextQuestion: 6 }, { tooltip: "", nextQuestion: 10000 }] }, 6: { title: "Title", options: [{ tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 14 }] }, 7: { title: "Title", options: [{ tooltip: "", nextQuestion: 17 }, { tooltip: "", nextQuestion: 17 }, { tooltip: "", nextQuestion: 17 }, { tooltip: "", nextQuestion: 17 }, { tooltip: "", nextQuestion: 17 }] }, 8: { title: "Title", options: [{ tooltip: "", nextQuestion: 9 }, { tooltip: "", nextQuestion: 9 }, { tooltip: "", nextQuestion: 9 }] }, 9: { title: "Title", options: [{ tooltip: "", nextQuestion: 10 }, { tooltip: "", nextQuestion: 10 }, { tooltip: "", nextQuestion: 10 }] }, 10: { title: "Title", options: [{ tooltip: "", nextQuestion: 11 }, { value: "Roof", attribute: "Flue Exit", tooltip: "", nextQuestion: 15 }] }, 11: { title: "Title", options: [{ tooltip: "", nextQuestion: 12 }, { tooltip: "", nextQuestion: 12 }] }, 12: { finalQuestion: true, input: true, placeHolder: 'e.g SWS' }, 13: { title: "Title", options: [{ tooltip: "", nextQuestion: 6 }, { tooltip: "", nextQuestion: 6 }] }, 14: { title: "Title", options: [{ tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 10000 }] }, 15: { title: "Title", options: [{ tooltip: "", nextQuestion: 12 }, { tooltip: "", nextQuestion: 12 }] }, 17: { title: "Title", options: [{ tooltip: "", nextQuestion: 8 }, { tooltip: "", nextQuestion: 8 }, { tooltip: "", nextQuestion: 8 }, { tooltip: "", nextQuestion: 8 }, { tooltip: "", nextQuestion: 8 }] }, 10000: { isError: true, title: "Finally, what is the first part of your postcode?", error: "Postcode" } };
    
    function* fnName(key, result = [key]) {
        let options = originalQuestions[key]?.options;
        if (!options) yield result
        else for (const id of new Set(options.map(v => v.nextQuestion)))
            yield* fnName(id, result.concat(id));
    }
    console.log("Prettify", Array.from(fnName(1), path => path.join(", ")))

    我简单地传递第一个问题 id (fnName(1)),在这种情况下它的编号为 1 因为这是第一个问题。 (originalQuestions[1].firstQuestion = true)

    【讨论】:

      【解决方案2】:

      派一些代理来探索您的路径。每个代理都会跟踪它的位置。它还可以克隆自己,以便在多条路径上进行探索:

      class Agent {
        constructor(questions, ...path){
          //data fields
          this.questions = questions;
          this.path = path;
          
          //derived fields
          const currentStep = this.path[this.path.length-1];
          this.currentQuetion = this.questions[currentStep];
          this.isFinished = 
            this.currentQuetion.finalQuestion
            || this.currentQuetion.isError
            || false;
        }
        
        clone(andNextStep) {
          return new Agent(this.questions, ...this.path, andNextStep);
        }
        
        possibleNext() {
          const nextSteps = (this.currentQuetion.options ?? [])
            .map(x => x.nextQuestion);
            
          return new Set(nextSteps);
        }
        
        takeStep() {
          if (this.isFinished)
            return [this];
            
          return Array.from(this.possibleNext(), step => this.clone(step));
        }
        
        static start(questions) {
          //find any possible first questions
          const first = Object.entries(questions)
            .filter(([key, q]) => q.firstQuestion);
          
          //for each first question create an agent
          let pathExplorers = first.map(([start]) => new Agent(questions, start));
          
          //get all agents to continue until they are all finished
          while (pathExplorers.some(x => !x.isFinished))
            pathExplorers = pathExplorers.flatMap(x => x.takeStep());
          
          return pathExplorers;
        }
      }
      
      const originalQuestions = { 1: { title: "Title", firstQuestion: true, options: [{ tooltip: "", nextQuestion: 2 }, { tooltip: "", nextQuestion: 2 }, { tooltip: "", nextQuestion: 10000 }] }, 2: { title: "Title", options: [{ tooltip: "", nextQuestion: 3 }, { tooltip: "", nextQuestion: 3 }, { tooltip: "", nextQuestion: 3 }, { tooltip: "", nextQuestion: 3 }] }, 3: { title: "Title", options: [{ tooltip: "", nextQuestion: 4 }, { tooltip: "", nextQuestion: 4 }, { tooltip: "", nextQuestion: 4 }] }, 4: { title: "Title", options: [{ tooltip: "", nextQuestion: 13 }, { tooltip: "", nextQuestion: 5 }] }, 5: { title: "Title", options: [{ tooltip: "", nextQuestion: 6 }, { tooltip: "", nextQuestion: 6 }, { tooltip: "", nextQuestion: 6 }, { tooltip: "", nextQuestion: 10000 }] }, 6: { title: "Title", options: [{ tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 14 }] }, 7: { title: "Title", options: [{ tooltip: "", nextQuestion: 17 }, { tooltip: "", nextQuestion: 17 }, { tooltip: "", nextQuestion: 17 }, { tooltip: "", nextQuestion: 17 }, { tooltip: "", nextQuestion: 17 }] }, 8: { title: "Title", options: [{ tooltip: "", nextQuestion: 9 }, { tooltip: "", nextQuestion: 9 }, { tooltip: "", nextQuestion: 9 }] }, 9: { title: "Title", options: [{ tooltip: "", nextQuestion: 10 }, { tooltip: "", nextQuestion: 10 }, { tooltip: "", nextQuestion: 10 }] }, 10: { title: "Title", options: [{ tooltip: "", nextQuestion: 11 }, { value: "Roof", attribute: "Flue Exit", tooltip: "", nextQuestion: 15 }] }, 11: { title: "Title", options: [{ tooltip: "", nextQuestion: 12 }, { tooltip: "", nextQuestion: 12 }] }, 12: { finalQuestion: true, input: true, placeHolder: 'e.g SWS' }, 13: { title: "Title", options: [{ tooltip: "", nextQuestion: 6 }, { tooltip: "", nextQuestion: 6 }] }, 14: { title: "Title", options: [{ tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 10000 }] }, 15: { title: "Title", options: [{ tooltip: "", nextQuestion: 12 }, { tooltip: "", nextQuestion: 12 }] }, 17: { title: "Title", options: [{ tooltip: "", nextQuestion: 8 }, { tooltip: "", nextQuestion: 8 }, { tooltip: "", nextQuestion: 8 }, { tooltip: "", nextQuestion: 8 }, { tooltip: "", nextQuestion: 8 }] }, 10000: { isError: true, title: "Finally, what is the first part of your postcode?", error: "Postcode" } };
      
      const result = Agent.start(originalQuestions)
        .map(agent => agent.path);
        
      console.log(
        //more concise printing
        result.map(path => path
          .map(step => String(step).padStart(2))
          .join(" -> "))
      );

      【讨论】:

        【解决方案3】:

        Nur 的精彩回答几乎就是我将如何解决这个问题的方法。我可能会建议一些改变,使这足以保证一个单独的帖子 -

        function* paths(t, key) {
          const { options } = t[key] ?? {}
          if (options == null) return yield [key]
          for (const id of new Set(options.map(v => v.nextQuestion)))
            for (const path of paths(t, id))
              yield [key, ...path]
        }
        
        const originalQuestions =
          { 1: { title: "Title", firstQuestion: true, options: [{ tooltip: "", nextQuestion: 2 }, { tooltip: "", nextQuestion: 2 }, { tooltip: "", nextQuestion: 10000 }] }, 2: { title: "Title", options: [{ tooltip: "", nextQuestion: 3 }, { tooltip: "", nextQuestion: 3 }, { tooltip: "", nextQuestion: 3 }, { tooltip: "", nextQuestion: 3 }] }, 3: { title: "Title", options: [{ tooltip: "", nextQuestion: 4 }, { tooltip: "", nextQuestion: 4 }, { tooltip: "", nextQuestion: 4 }] }, 4: { title: "Title", options: [{ tooltip: "", nextQuestion: 13 }, { tooltip: "", nextQuestion: 5 }] }, 5: { title: "Title", options: [{ tooltip: "", nextQuestion: 6 }, { tooltip: "", nextQuestion: 6 }, { tooltip: "", nextQuestion: 6 }, { tooltip: "", nextQuestion: 10000 }] }, 6: { title: "Title", options: [{ tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 14 }] }, 7: { title: "Title", options: [{ tooltip: "", nextQuestion: 17 }, { tooltip: "", nextQuestion: 17 }, { tooltip: "", nextQuestion: 17 }, { tooltip: "", nextQuestion: 17 }, { tooltip: "", nextQuestion: 17 }] }, 8: { title: "Title", options: [{ tooltip: "", nextQuestion: 9 }, { tooltip: "", nextQuestion: 9 }, { tooltip: "", nextQuestion: 9 }] }, 9: { title: "Title", options: [{ tooltip: "", nextQuestion: 10 }, { tooltip: "", nextQuestion: 10 }, { tooltip: "", nextQuestion: 10 }] }, 10: { title: "Title", options: [{ tooltip: "", nextQuestion: 11 }, { value: "Roof", attribute: "Flue Exit", tooltip: "", nextQuestion: 15 }] }, 11: { title: "Title", options: [{ tooltip: "", nextQuestion: 12 }, { tooltip: "", nextQuestion: 12 }] }, 12: { finalQuestion: true, input: true, placeHolder: 'e.g SWS' }, 13: { title: "Title", options: [{ tooltip: "", nextQuestion: 6 }, { tooltip: "", nextQuestion: 6 }] }, 14: { title: "Title", options: [{ tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 7 }, { tooltip: "", nextQuestion: 10000 }] }, 15: { title: "Title", options: [{ tooltip: "", nextQuestion: 12 }, { tooltip: "", nextQuestion: 12 }] }, 17: { title: "Title", options: [{ tooltip: "", nextQuestion: 8 }, { tooltip: "", nextQuestion: 8 }, { tooltip: "", nextQuestion: 8 }, { tooltip: "", nextQuestion: 8 }, { tooltip: "", nextQuestion: 8 }] }, 10000: { isError: true, title: "Finally, what is the first part of your postcode?", error: "Postcode" } }
        
        for (const path of paths(originalQuestions, 1))
          console.log(path.join(" -> "))
        .as-console-wrapper { min-height: 100%; }
        1 -> 2 -> 3 -> 4 -> 13 -> 6 -> 7 -> 17 -> 8 -> 9 -> 10 -> 11 -> 12
        1 -> 2 -> 3 -> 4 -> 13 -> 6 -> 7 -> 17 -> 8 -> 9 -> 10 -> 15 -> 12
        1 -> 2 -> 3 -> 4 -> 13 -> 6 -> 14 -> 7 -> 17 -> 8 -> 9 -> 10 -> 11 -> 12
        1 -> 2 -> 3 -> 4 -> 13 -> 6 -> 14 -> 7 -> 17 -> 8 -> 9 -> 10 -> 15 -> 12
        1 -> 2 -> 3 -> 4 -> 13 -> 6 -> 14 -> 10000
        1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 17 -> 8 -> 9 -> 10 -> 11 -> 12
        1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 17 -> 8 -> 9 -> 10 -> 15 -> 12
        1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 14 -> 7 -> 17 -> 8 -> 9 -> 10 -> 11 -> 12
        1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 14 -> 7 -> 17 -> 8 -> 9 -> 10 -> 15 -> 12
        1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 14 -> 10000
        1 -> 2 -> 3 -> 4 -> 5 -> 10000
        1 -> 10000
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-08-03
          • 1970-01-01
          • 1970-01-01
          • 2021-07-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-08-19
          相关资源
          最近更新 更多