#javascript
Вопрос:
Я создал что-то, чтобы найти возможные пути того, что пользователь может ввести в анкету. Однако логика должна немного измениться, чтобы можно было найти возможный путь даже с пропущенным вопросом.
Текущее Решение:
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"
}
};
class QuestionAnswerPossibilities {
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 QuestionAnswerPossibilities(this.questions, ...this.path, andNextStep);
}
possibleNext() {
const nextSteps = (this.currentQuetion.options ? 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 QuestionAnswerPossibilities(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 MatchingAnswerPaths = (answerPaths, questionsAnswered) => {
let possiblePaths = [];
answerPaths.forEach(answerPath => {
let matchingPathFound = questionsAnswered.every((r, index) => {
return answerPath[index] === r;
});
if (matchingPathFound) {
possiblePaths.push(answerPath);
}
});
return possiblePaths;
}
const GetLongestAnswerPath = (possiblePaths) => {
let longest = 0;
let longestPath = [];
possiblePaths.forEach((path) => {
if (path.length > longest) {
longestPath = [path];
longest = path.length;
} else if (path.length == longest) {
longestPath.push(path);
}
});
if (longestPath.length > 0) {
return longestPath[0];
}
}
// Answered Paths
let answeredPaths = [1, 2, 3, 5];
// Get possibilities
let possibilities = QuestionAnswerPossibilities.start(originalQuestions);
possibilities = possibilities.map(agent => agent.path);
possibilities = possibilities.map(path => path.map(step => String(step)));
// Get Matched paths
let matchedPaths = MatchingAnswerPaths(possibilities, answeredPaths);
console.log(possibilities);
console.log(matchedPaths);
Работает с:
answeredPaths = [1, 2, 3, 4, 5];
Неудача с:
answeredPaths = [1, 2, 3, 5];
Причины его неудачи в том, что он находит все возможности, основанные на правильном порядке, он не учитывает пропущенный вопрос, поэтому 3 -> 5
вместо стандартного порядка 3 -> 4 -> 5
;
Возможное решение:
При пропуске от 3 до 5 я заставляю вопрос 4 быть добавленным в пути ответов. Однако я не хочу писать для этого какой-то статический код. Я хочу, чтобы совпадающие пути решили эту проблему.
Ответ №1:
Перепробовав множество решений, я наконец нашел одно, которое действительно работает:
Это также будет охватывать несколько пропусков, например
answeredPaths = [1, 2, 3, 5];
answeredPaths = [1, 2, 3, 6];
answeredPaths = [1, 3, 6];
Каким был исходный код:
const MatchingAnswerPaths = (answerPaths, questionsAnswered) => {
let possiblePaths = [];
answerPaths.forEach(answerPath => {
let matchingPathFound = questionsAnswered.every((r, index) => {
return answerPath[index] === r;
});
if (matchingPathFound) {
possiblePaths.push(answerPath);
}
});
return possiblePaths;
}
Фиксированный код:
const MatchingAnswerPaths = (answerPaths, questionsAnswered) => {
let possiblePaths = [];
answerPaths.forEach(answerPath => {
let matchingPathFound = questionsAnswered.every((r, index) => {
let answerPathIndex = answerPath.indexOf(r);
return answerPath[answerPathIndex] === r;
});
if (matchingPathFound) {
possiblePaths.push(answerPath);
}
});
return possiblePaths;
}
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"
}
};
class QuestionAnswerPossibilities {
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 QuestionAnswerPossibilities(this.questions, ...this.path, andNextStep);
}
possibleNext() {
const nextSteps = (this.currentQuetion.options ? 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 QuestionAnswerPossibilities(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 MatchingAnswerPaths = (answerPaths, questionsAnswered) => {
let possiblePaths = [];
answerPaths.forEach(answerPath => {
let matchingPathFound = questionsAnswered.every((r, index) => {
let answerPathIndex = answerPath.indexOf(r);
return answerPath[answerPathIndex] === r;
});
if (matchingPathFound) {
possiblePaths.push(answerPath);
}
});
return possiblePaths;
}
const GetLongestAnswerPath = (possiblePaths) => {
let longest = 0;
let longestPath = [];
possiblePaths.forEach((path) => {
if (path.length > longest) {
longestPath = [path];
longest = path.length;
} else if (path.length == longest) {
longestPath.push(path);
}
});
if (longestPath.length > 0) {
return longestPath[0];
}
}
// Answered Paths
let answeredPaths = ["1", "2", "3", "5", "6"];
// Get possibilities
let possibilities = QuestionAnswerPossibilities.start(originalQuestions);
possibilities = possibilities.map(agent => agent.path);
possibilities = possibilities.map(path => path.map(step => String(step)));
// Get Matched paths
let matchedPaths = MatchingAnswerPaths(possibilities, answeredPaths);
//console.log(possibilities);
console.log(matchedPaths);