【问题标题】:Recursively process JSON array to find common values across all object in array递归处理 JSON 数组以查找数组中所有对象的公共值
【发布时间】:2019-06-21 19:11:55
【问题描述】:

在过去的几天里,我一直在努力递归处理这个 JSON 结构,希望有人可以帮助我。

我有一个包含多个 JSON 对象的数组。每个对象代表一个问题并有 1 个或多个可能的答案。每个答案包含 1 个或多个可能的条件,这些条件又包含 1 个数据点和 1 个 requiredValue。

JSON 对象

[
  {
    "originalQ": "Have you been to hospital?",
    "originalA": "No",
    "potentialAnswers": [
      {
        "conditions": [
          {
            "datapoint": "Hospitalization",
            "assoicatedValue": "more than 2 years ago "
          }
        ]
      },
      {
        "conditions": [
          {
            "datapoint": "Hospitalization",
            "assoicatedValue": "never"
          }
        ]
      }
    ]
  },
  {
    "originalQ": "Has a medical professional diagnosed you?",
    "originalA": "No",
    "potentialAnswers": [
      {
        "conditions": [
          {
            "datapoint": "OtherDiagnosis",
            "assoicatedValue": "has never"
          },
          {
            "datapoint": "Hospitalization",
            "assoicatedValue": "never"
          }
        ]
      }
    ]
  },
  {
    "originalQ": "Are you taking medication?",
    "originalA": "Yes",
    "potentialAnswers": [
      {
        "conditions": [
          {
            "datapoint": "Medications",
            "assoicatedValue": "1-3"
          }
        ]
      },
      {
        "conditions": [
          {
            "datapoint": "Medications",
            "assoicatedValue": "4 or more"
          }
        ]
      }
    ]
  },
  {
    "originalQ": "How many different medications do you take?",
    "originalA": "4 or more",
    "potentialAnswers": [
      {
        "conditions": [
          {
            "datapoint": "Medications",
            "assoicatedValue": "4 or more"
          }
        ]
      }
    ]
  }
]

我需要获取一个 JSON 对象,其中包含 datapoint:assoicatedValue 对,这将允许我们在每个问题的 potentialAnswer 数组中为每个问题对象找到一个匹配元素。

数据点总是比答案少,所以我需要知道我可以为每个数据点分配什么值,以便在每个问题的 potentialAnswer 数组中拥有 1 个有效对象。如果没有这种可能的组合,我需要注意这一点。

最终,每个数据点只能有一个值,因此无论为它们分配什么值,都不会与其他问题的答案发生冲突。这将被视为总体对象答案。

一些补充信息:

  1. Every 是动态生成的,即数据点名称可以在运行之间更改(但在同一运行的对象之间保持一致),问题对象的数量会发生变化。
  2. 在某些情况下无法找到数据点值,在这种情况下,函数应该返回该信息。

以下结果与每个问题中至少一个可能的答案相匹配。

要求的结果

{
  "Hospitalization": "never ",
  "OtherDiagnosis": "has never",
  "Medications": "4 or more"
}

我已经尝试了多种方法来解决这个问题,但总是遇到我无法解决的问题。下面的代码是我得到的最接近的。它在大多数情况下都有效,但如果在最后一个问题对象中遇到问题,它似乎会出现问题。

代码尝试

let allQuestionData = require('./datafile.1.json');

findCorrectAnswerCombination(allQuestionData);

function findCorrectAnswerCombination(allQuestionData) {
    console.log(ProcessNextQuestion(allQuestionData));
}

//This function will run all of the next questions
function ProcessNextQuestion(allQuestions, startingIndex = 0, dpObj = {}, questionNum = 1) {
    try{
        //create deep copy of Obj
        let copyDpObj = JSON.parse(JSON.stringify(dpObj))

        //Loop through all of the remaining questions
        for (let i = startingIndex; i < allQuestions.length; i++) {
            let question = allQuestions[i];

            for (let answerNum = 0; answerNum < question.potentialAnswers.length; answerNum++) {
                let answer = question.potentialAnswers[answerNum];

                //Determine if the current potential answer fits with the values already in the dpObj
                if (doesAnswerFitInCurrentDPObject(answer, copyDpObj)) {

                    //Add the new datapoints to the doObj if there are any new dps
                    let tempDPObj = addValuesToDpObj(answer, dpObj);

                    //if this is the final question then we have a valid path
                    if (questionNum === allQuestions.length) {
                        return tempDPObj;
                    } else {
                        //recurively run on remaining questions
                        return ProcessNextQuestion(allQuestions, i + 1, tempDPObj, questionNum + 1);
                    }
                }
            }    
        }
        return 'No matching values found'

    }catch(err){
        throw new Error(err)
    }

}

function doesAnswerFitInCurrentDPObject(answer, dpObj) {

    for (const condition of answer.conditions) {
        if (dpObj.hasOwnProperty(condition.datapoint) && dpObj[condition.datapoint] !== condition.assoicatedValue) {
            return false;
        }
    }
    return true;
}

function addValuesToDpObj(answer, currentDpObj) {
    let copyObj = JSON.parse(JSON.stringify(currentDpObj));

    for (const condition of answer.conditions) {
        copyObj[condition.datapoint] = condition.assoicatedValue;
    }

    return copyObj;
}

【问题讨论】:

  • 为什么期望的结果应该是 "Hospitalization": "never " 而不是 "Hospitalization": "more than 2 years ago " ? (我猜“never”后面的空格是错字?)从文本中,听起来更像是你想要"Hospitalization": [...all possible answers...],而一个空数组可能意味着没有assoicatedValue
  • "Hospitalization": 不应该是因为第二个问题对象有两个条件,第二个是住院。如果值为"more than 2 years ago",这将与第二个问题的唯一可能答案相冲突。我需要每个数据点都有一个值,因为它们代表将输入 associatedValue 的应用程序中的单个字段

标签: javascript arrays node.js json recursion


【解决方案1】:

在头撞墙之后,我最终找到了我正在寻找的解决方案。

我没有正确处理值的返回。如果找到正确的值,我需要在调用递归后检查。如果是,我需要另一个 return 语句来结束该循环。在这种情况下,我的循环将一直存在。最初无论是否找到该值都会返回。

//This function will run all of the next questions
function ProcessNextQuestion(allQuestions, startingIndex = 0, dpObj = {}, questionNum = 1) {
    try {
        //create deep copy of Obj
        let copyDpObj = JSON.parse(JSON.stringify(dpObj))

        //Loop through all of the remaining questions
        for (let i = startingIndex; i < allQuestions.length; i++) {
            let question = allQuestions[i];

            for (let answerNum = 0; answerNum < question.potentialAnswers.length; answerNum++) {
                let answer = question.potentialAnswers[answerNum];

                //Determine if the current potential answer fits with the values already in the dpObj
                if (doesAnswerFitInCurrentDPObject(answer, copyDpObj)) {

                    //Add the new datapoints to the doObj if there are any new dps
                    let tempDPObj = addValuesToDpObj(answer, dpObj);

                    //if this is the final question then we have a valid path
                    if (questionNum === allQuestions.length) {
                        return tempDPObj;
                    } else {

              //******************
              // This is what I needed to add
              //******************
                        //recurively run on remaining questions
                        let processingResultFound = ProcessNextQuestion(allQuestions, i + 1, tempDPObj, questionNum + 1);
                        if (processingResultFound !== 'No matching values found') {
                            return processingResultFound;
                        }
              //******************

                    }
                }
            }
        }
        return 'No matching values found'

    } catch (err) {
        throw new Error(err)
    }
}

【讨论】:

    猜你喜欢
    • 2015-10-14
    • 1970-01-01
    • 2022-11-27
    • 1970-01-01
    • 2023-01-12
    • 2020-10-09
    • 2018-02-14
    • 2019-03-27
    相关资源
    最近更新 更多