Maximilian Christian
Maximilian Christian

Reputation: 43

Javascript search through object

I'm unfortunately still not quite familiar with objects in JS and only programming a bit for my PhD in psychology, so I don't have great programming skills. I've managed to create a nice object which captures my data structure pretty well:

var items = {
  anamnese_akut: [{
    id: 1,
    question: 'Haben Sie die Beschwerden zum ersten Mal?',
    answer: 'Ja, also so etwas ist noch nie passiert.'
  }, {
    id: 2,
    question: 'Haben Sie in den letzten Wochen unbeabsichtigt Gewicht verloren?',
    answer: 'Nein, bestimmt nicht.'
  }],
  anamnese_allgemein: [{
    id: 3,
    question: 'Sind bei Ihnen Vorerkrankungen bekannt?',
    answer: 'Eigentlich nicht, nein.'
  }, {
    id: 4,
    question: 'Wurden Sie schon mal operiert?',
    answer: 'Ich hatte eine Blinddarmoperation als Kind, und in den letzten zwei Jahren dreimal eine Ausschabung nach Fehlgeburten.'
  }]
};    

I now want to search for an input variable which contains exactly one of these 4 questions, but can come from both categories. I've already managed to do something like this with an unnested object, using the code from here: JS search in object values, but I cannot get it to work and have no idea how to adapt it to an object with categories like anamnese_akut and anamnese_allgemein.

How can I adapt a search for this? After comparing the input with the questions I want to have an index, so that I can give an output of the corresponding answer to the found question.

Upvotes: 0

Views: 853

Answers (5)

Nina Scholz
Nina Scholz

Reputation: 386578

For getting the category and the index of the inner array, you could oiterate the keys of the given object an then iterate the inner array for checking the questions. If the given string is equal to a question property, then the actual category and index is returned. If no result is found, undefined is returned.

function find(object, search) {
    var result;

    Object.keys(object).some(function (k) {
        return object[k].some(function (o, i) {
            if (o.question === search) {
                result = { category: k, index: i };
                return true;
            }
        });
    });

    return result;
}

var items = { anamnese_akut: [{ id: 1, question: 'Haben Sie die Beschwerden zum ersten Mal?', answer: 'Ja, also so etwas ist noch nie passiert.' }, { id: 2, question: 'Haben Sie in den letzten Wochen unbeabsichtigt Gewicht verloren?', answer: 'Nein, bestimmt nicht.' }], anamnese_allgemein: [{ id: 3, question: 'Sind bei Ihnen Vorerkrankungen bekannt?', answer: 'Eigentlich nicht, nein.' }, { id: 4, question: 'Wurden Sie schon mal operiert?', answer: 'Ich hatte eine Blinddarmoperation als Kind, und in den letzten zwei Jahren dreimal eine Ausschabung nach Fehlgeburten.' }] };

console.log(find(items, 'Sind bei Ihnen Vorerkrankungen bekannt?'));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Jankapunkt
Jankapunkt

Reputation: 8423

I think there is another way of structuring your data here. You can avoid arrays and use referencing by object properties. The advantage is, that you can access the values without a "search" in terms of iterations but by the object's property hash.

Note: for readability purposes, I have only used a reduced subset of your data in the examples.

Example A - Base on index number

var anamnese_akut = {
    q: {
  	1:'Haben Sie die Beschwerden zum ersten Mal?',
	2: 'Haben Sie in den letzten Wochen unbeabsichtigt Gewicht verloren?',
    },
  
    a: {
  	1:'Ja, also so etwas ist noch nie passiert.',
        2:'Nein, bestimmt nicht.'
    },
};

console.log(anamnese_akut.q['1']);
console.log(anamnese_akut.a['1']);

With this example you would base your data on the index number (1, 2, 3...) and access your questions and answers by that number.

Advantage: Less error prone, because the index is short and can be stored as number.

Disadvantage: Index number must be known within overall context of q and a.

Example B - Access by Id but with different structure

var questions = {
    anamnese_akut: {
  	1:'Haben Sie die Beschwerden zum ersten Mal?',
        2:'Haben Sie in den letzten Wochen unbeabsichtigt Gewicht verloren?',
    },
};

var answers = {
    anamnese_akut: {
  	1: 'Ja, also so etwas ist noch nie passiert.',
        2: 'Nein, bestimmt nicht.',
    },
};

console.log(questions.anamnese_akut['1']);
console.log(answers.anamnese_akut['1']);

Advantages: Decoupled questions and answers, for access only the index is required (as in Example A)

Disadvantage: More work on the structural design level, since there is a little bit more redundancy here (since we have now two objects with the anamnese_akut entry).

Example C - Access by question

var anamnese_akut = {
    'Haben Sie die Beschwerden zum ersten Mal?' : 'Ja, also so etwas ist noch nie passiert.',
};

console.log(anamnese_akut['Haben Sie die Beschwerden zum ersten Mal?']);

Advantages: Answer immediatly returned

Disadvantage: Question string needs to be strictly as given in the object or the access fails and returns undefined.

Personally I would go for Example B since it allows me to split question and answer data contexts (which may become important, depending on your application use case) and still allows me to access by one given index number.

Upvotes: 1

Jonas Wilms
Jonas Wilms

Reputation: 138267

const input = "whatever";

for(const category in items){
 for(const question of items[category]){
   if(question.question === input){
     //do whatever
     //optionally: return; 
   }
 }
}

In action

or if you prefer a functional approach:

const input = "whatever";
const result = Object.values(items).reduce(
   (res,category)=> res || category.find(obj => obj.question === input ), false
);

In action

Upvotes: 0

marvel308
marvel308

Reputation: 10458

you can do it in the following way

var items = {
  anamnese_akut: [{
    id: 1,
    question: 'Haben Sie die Beschwerden zum ersten Mal?',
    answer: 'Ja, also so etwas ist noch nie passiert.'
  }, {
    id: 2,
    question: 'Haben Sie in den letzten Wochen unbeabsichtigt Gewicht verloren?',
    answer: 'Nein, bestimmt nicht.'
  }],
  anamnese_allgemein: [{
    id: 3,
    question: 'Sind bei Ihnen Vorerkrankungen bekannt?',
    answer: 'Eigentlich nicht, nein.'
  }, {
    id: 4,
    question: 'Wurden Sie schon mal operiert?',
    answer: 'Ich hatte eine Blinddarmoperation als Kind, und in den letzten zwei Jahren dreimal eine Ausschabung nach Fehlgeburten.'
  }]
};

let query = 'Wurden Sie schon mal operiert?';
let answer = Object.keys(items).reduce(function(a, b){
    let val = items[b].reduce(function(a, b){
        if(b.question == query){
            return b.answer;
        }
    }, "not available")
    if(val == "not available")
        return a;
    return val;
}, "not available");
console.log(answer);

Upvotes: 0

UncleDave
UncleDave

Reputation: 7188

If I take your meaning correctly: your input is question text and it needs to be matched to one of these objects, then this should do the trick:

var input = 'Haben Sie die Beschwerden zum ersten Mal?' // For demo purposes.
var output = items.anamnese_akut.find(x => x.question === input) || items.anamnese_allgemein.find(x => x.question === input)

Of course this isn't the most elegant solution, especially if you add more anamnese objects.

Upvotes: 0

Related Questions