Search code examples
javascripttypescriptdesign-patternsanti-patternsarchitectural-patterns

Best way design and generate unique strings from an array of objects for mapping


The problem I am trying to solve is how best to generate a unique string from a set of question/answer strings.

So say an end user fills out a questionnaire and answers the following:

   [
       {
           "is there a problem": "yes"
       },
       {
           "what is it?": "product is damaged"
       },
       {
           "do you want a refund?": "yes"
       }
   ]

I need to generate a string that represents these questions and answers and then map that to a templateId to send a templated message to.

I thought about simply running a foreach and adding all the questions and responses together but the issue there is what if the questions and answers change or additional questions are added that we are not interested in for sending message purposes.

Should I use something like find or a hashtable type of look up instead so I am only picking out the questions I need. I am a bit worried about performance here too but it shouldn't be a big deal as this set of questions/answers should remain relatively small.

I was also wondering about this string -> templateId mapping, what is the best way to store this information, a simple object works fine?

Clarification:

It doesn't have to be unique or be a hashmap. Basically we have email templates in the backend to send messages. In the frontend we need to figure out which email template to use given the set of responses to the questions. So my simple solution was to append the questions/answers together to generate a string, i.e "isThereProblemYesWhatisIt?ProductDamagedDoyouwantaRefund?Yes"

i.e Available templates in the backend:

productDamaged
productLost

Mapping created in the front end.

"isThereProblem?YesWhatisIt?ProductDamagedDoyouwantaRefund?Yes" : 
"productDamaged"

Thanks


Solution

  • With a small set of questions and answers, an enumeration is feasible and maintainable. Something like this:

    const userSubmission = [{
        "is there a problem": "yes"
      },
      {
        "what is it?": "product is damaged"
      },
      {
        "do you want a refund?": "yes"
      }
    ]
    
    const userSubmission2 = [{
        "is there a problem": "yes"
      },
      {
        "what is it?": "product is damaged"
      },
      {
        "do you want a refund?": "no"
      }
    ]
    
    const templates = {
      "is there a problem-yeswhat is it?-product is damageddo you want a refund?-yes": "templateForDamagedAndRefundWanted",
      "is there a problem-yeswhat is it?-product is damageddo you want a refund?-no": "templateForDamagedAndRefundNotWanted"
    }
    
    function keyFromSubmission(submission) {
      return submission.reduce((acc, obj) => {
        let [key, value] = Object.entries(obj)[0]
        acc += `${key}-${value}`
        return acc
      }, "")
    }
    
    
    const key = keyFromSubmission(userSubmission)
    console.log(templates[key])
    
    console.log("\nOr, with a different user submission...")
    const key2 = keyFromSubmission(userSubmission2)
    console.log(templates[key2])

    EDIT

    You can plan for textual changes to questions and answers by adding a level of indirection. With this, questions, answers and their variants are represented symbolically.

    const questions = [{
        questionId: "q1",
        text: "what is the problem?",
        answers: [{
          answerId: "a1",
          text: "product was broken"
        }, {
          answerId: "a2",
          text: "product didn't arrive"
        }]
      },
      {
        questionId: "q2",
        text: "do you want a refund?",
        answers: [{
          answerId: "a1",
          text: "yes"
        }, {
          answerId: "a2",
          text: "no"
        }]
      }
    ]
    
    const userSubmission = [{
        "what is the problem?": "product didn't arrive"
      },
      {
        "do you want a refund?": "yes"
      }
    ]
    
    function userSubmissionAsSymbols(submission) {
      return submission.map(s => {
        let [key, value] = Object.entries(s)[0]
        let question = questions.find(q => q.text === key)
        let answer = question.answers.find(a => a.text === value)
        return `${question.questionId}-${answer.answerId}`
      })
    }
    
    console.log(userSubmissionAsSymbols(userSubmission))

    With this, you do the same thing as before, mapping the keys derived from the q/a values to templates. In this version, though, the text presented to the user can be changed arbitrarily.