Hoe om te gaan met conditionele vragen?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Tony L
  • Registratie: September 2005
  • Laatst online: 07-11-2015
Ik ben een simpele vragenlijst in elkaar aan het draaien en tot zover werkt alles naar behoren. Tot het moment dat ik aan conditionele vragen dacht en dit wilde implementeren >:)

Wat is het probleem
Ik heb GEEN idee hoe ik de vragenlijst op een degelijke manier moet opzetten zonder dat het een complexe puinzooi wordt...

Denk aan de volgende vragenlijst:
code:
1
2
3
4
5
6
7
8
9
10
11
12
1. Hou je van spruitjes?
    - Ja
    - Nee
    
    1.1 Waarom niet? [Conditie 1.1 = Nee]
    - Omdat ik het vies vind
    - Omdat ik liever spinazie eet
    
    1.2 Hoe zou je spruitjes koken om het wel lekker te maken? [Conditie 1.1 = Nee]
    - Geen idee
    - Roerbakken met spekjes
2. Etc.


De algemene structuur met validatie en dergelijke heb ik al helemaal werkend. Echter het conditionele aspect maakt het lastig voor me. Ik had voorheen gewoon een IList<QuestionControl> van vragen die ik wilde stellen. Dit was een simpele list en het enige wat ik hoefde te doen was de index te verhogen of te verlagen (afhankelijk van of er op "volgende" of "vorige" werd gedrukt).

Echter weet ik nu niet goed hoe ik het afgelegde path moet vasthouden EN weten wat de volgende vraag moet worden. Mijn idee was alsvolgt, ik hou gewoon een IList<QuestionControl> bij voor alle vragen die ik beantwoord hebt. Op deze manier kan ik doodsimpel terug in de vragenlijst. Ik hoef dan alleen de index te verlagen. Maar hoe ga ik dan om met de volgende knop? Ik zal een korte uitleg geven van mijn huidige structuur.

C#:
1
2
3
4
5
public class QuestionControl {
    public bool IsValid;
    public bool IsMandatory;
    public IList<int, QuestionControl> SubQuestions;
}


Ik heb één hoofdklasse QuestionControl en drie subclasses genaamd:
- TextQuestionControl (voor de openvragen)
- DropdownQuestionControl (voor de combobox vragen)
- CheckListQuestionControl (voor wanneer er meerdere mogelijkheden zijn).

De SubQuestions zijn eigenlijk alleen relevant voor DropdownQuestionControls en CheckListQuestionControls en ik kan aangeven per SubQuestion wat de antwoord index is. Ik pak de bovenstaande vragenlijst er even bij in pseudo-code hoe ik het in gedachten had:

C#:
1
2
3
4
5
6
7
DropdownQuestionControl question1 = new DropdownQuestionControl("Hou je van spruitjes?", new string[] { "Ja", "Nee" });

DropdownQuestionControl question1dot1 = new DropdownQuestionControl("Waarom niet?", new string[] { "Omdat ik het vies vind", "Omdat ik liever spinazie eet" });
question1.SubQuestions.Add(1, question1dot1); // Deze subvraag moet dus getoond worden wanneer er voor de tweede optie "Nee" is gekozen bij question1

DropdownQuestionControl question1dot2 = new DropdownQuestionControl("Hoe zou je spruitjes koken om het wel lekker te maken?", new string[] { "Geen idee", "Roerbakken met spekjes" });
question1.SubQuestions.Add(1, question1dot2); // Andere subvraag, ook wanneer bij question1, optie 2 wordt gekozen



En hier begint mijn probleem eigenlijk. Op het moment dat ik de diepte in ga met de subvragen, weet ik niet goed hoe ik het knap kan oplossen. Stel dat ik bij question1dot2 ben, hoe weet ik dan dat er nog een subvraag bij vraag 1 hoort? Question1dot2 moet namelijk OOK gevraagd worden, aangezien dit dezelfde conditie heeft als question1dot1 (namelijk optie 2).

Ik kan natuurlijk recursief aan de parent's vragen of de child al beantwoord is en zo niet dan wordt dit de volgende vraag, echter lijkt me dit niet zo heel efficiënt. Zijn er toevallig design patterns die specifiek dit probleem tackelen?

Elke hulp wordt zeer gewaardeerd!!

PSN: Norfirin


Acties:
  • 0 Henk 'm!

  • Afvalzak
  • Registratie: Oktober 2008
  • Laatst online: 31-08 12:02

Afvalzak

Zet jij mij even buiten?

Is het niet handig om een database te koppelen met alle vragen en antwoorden en subvragen?

Question
[id] [question] [parent] [requiredanswerid]
1 | Hou je van spruitjes? | null | null
2 | Waarom hou je niet van spruitjes? | 1 | 2


QuestionAnswer
[id] [questionid] [answer]
1 | 1 | Ja
2 | 1 | Nee
3 | 2 | Waarom niet?
4 | 2 | Wat moeten we doen ... ?


Weet niet of dit je helpt, en het is waarschijnlijk niet helemaal netjes op database vlak, maar het gaat om het idee ;)

[ Voor 15% gewijzigd door Afvalzak op 26-01-2011 22:36 . Reden: toevoeging. ]

Last.fm | Code Talks


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Eigenlijk is de aanpassing redelijk simpel. Het lastige deel zit hem in de conditie. Hier zul je iets voor moeten verzinnen. Eigenlijk moet je aan een vraag kunnen vragen of hij gesteld moet worden. De vorige volgende is vervolgens erg simpel. Dat wordt niet een

index++

, maar een

do
index++
until (vragen[index].isVisible or index == vragen.length)

(2e check kijkt of je al klaar bent)
Hetzelfde geld voor vorige, maar dan de andere kant op natuurlijk.

De enige eisen die je verder moet stellen is dat je eerste vraag altijd zichtbaar is en dat de vragen altijd in chronologische volgorde doorlopen moeten worden, maar door alleen vorige en volgende aan te bieden gaat dat wel goed.

@afvalzak: Op die manier beperk je de condities wel enorm (enkel afhankelijk van 1 antwoord) terwijl je aan de andere kant wel een stuk redundantie introduceert in de database. Daarnaast kun jij maar 1 niveau diep.

[ Voor 13% gewijzigd door Janoz op 26-01-2011 22:56 ]

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Afvalzak
  • Registratie: Oktober 2008
  • Laatst online: 31-08 12:02

Afvalzak

Zet jij mij even buiten?

@Janoz, dat klopt, het was ook maar een kleine opzet, je zou het geheel natuurlijk kunnen uitbreiden zover als je wilt, eventueel met een parent children tabel waarmee de antwoorden en vragen weer aan elkaar te koppelen zijn, zodat je niet overal 'null' etc. hoeft in te vullen.

Ik geloof dat de vragen/antwoorden nu hard-coded worden opgeslagen, en dat is, afhankelijk van hoevaak en wanneer je de applicatie wilt gaan gebruiken ook niet het beste idee ;)

Last.fm | Code Talks


Acties:
  • 0 Henk 'm!

  • Tony L
  • Registratie: September 2005
  • Laatst online: 07-11-2015
Janoz schreef op woensdag 26 januari 2011 @ 22:51:
Eigenlijk moet je aan een vraag kunnen vragen of hij gesteld moet worden. De vorige volgende is vervolgens erg simpel. Dat wordt niet een

index++

, maar een

do
index++
until (vragen[index].isVisible or index == vragen.length)

(2e check kijkt of je al klaar bent)
Hetzelfde geld voor vorige, maar dan de andere kant op natuurlijk.
Is het wel handig om een vraag zelf te laten weten of ie getoond moeten worden of niet? Zorg je er dan niet voor dat een vraag eigenlijk meer weet dan noodzakelijk? Het leek me juist handig om de Survey zelf leidend te maken zodat de vragen zelf niets meer zijn dan relatief "domme" objecten.

Begijp ik het trouwens goed dat jij de vragenlijst niet als een tree-structuur ziet maar als een list waarbij elke vraag weet onder welke condities de vraag getoond moet worden? Je bent dan inderdaad in 1 keer van het diepte verhaal af en je kan relatief eenvoudig door de lijst heen lopen.

code:
1
2
3
4
1. Vraag 1
2. Vraag 1.1 (Conditie Vraag 1 = Nee)
3. Vraag 1.1 (Conditie Vraag 1 = Nee)
4. Vraag 2


Een nadeel hiervan is dat je goed moet weten waar je de vragen neerzet. Je kan een vraag met condities namelijk nooit eerder stellen dan de vraag waar de condities vandaan komen.
afvalzak schreef op woensdag 26 januari 2011 @ 22:59:
Ik geloof dat de vragen/antwoorden nu hard-coded worden opgeslagen, en dat is, afhankelijk van hoevaak en wanneer je de applicatie wilt gaan gebruiken ook niet het beste idee ;)
Ik ben nu met een prototype bezig, daar is nog geen database voor nodig ;)
Uiteindelijk komt alles mooi in een database maar ik wil eerst de algemene structuur werkend hebben.

PSN: Norfirin


Acties:
  • 0 Henk 'm!

Verwijderd

Kun je niet gewoon met een goto werken?
Dus elke conditie van een vraag heeft een goto naar een volgende vraag.

Acties:
  • 0 Henk 'm!

Verwijderd

:S Kun je dat iets verduidelijken want dat begrijp ik niet.

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Tony L schreef op woensdag 26 januari 2011 @ 23:12:
Een nadeel hiervan is dat je goed moet weten waar je de vragen neerzet. Je kan een vraag met condities namelijk nooit eerder stellen dan de vraag waar de condities vandaan komen.
Maar dat is evident. Je kunt natuurlijk nooit een vraag gaan stellen die afhankelijk is van een vraag die erna komt. Eventueel zou je in je 'vragen maak'-deel van je software een soort validatie op kunnen nemen om te controleren dat er geen 'voorwaartse afhankelijkheden zijn'.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Reptile209
  • Registratie: Juni 2001
  • Laatst online: 19:07

Reptile209

- gers -

Als je nu bij *iedere* vraag *alle* antwoorden voorziet van een NextQuestionNumber-eigenschap. Bij simpele vragen is dat stomweg het volgende vraagnummer, maar daar waar routering (volgens mij heet het zo in questionaires) van belang is kan je verschillende paden gaan definieren. Zo werken (hardcopy)belastingformulieren e.d. eigenlijk ook: "ga verder met vraag 4c".

Dus zoiets:
code:
1
2
3
4
5
6
7
8
9
10
11
12
1. Hou je van spruitjes?
    - Ja [ga verder met 2]
    - Nee [ga verder met 1.1]
    
    1.1 Waarom niet? 
    - Omdat ik het vies vind [ga verder met 1.2]
    - Omdat ik liever spinazie eet [ga verder met 5]
    
    1.2 Hoe zou je spruitjes koken om het wel lekker te maken? 
    - Geen idee [ga verder met 2]
    - Roerbakken met spekjes [ga verder met 2]
2. Etc.


En als je dan bij het aanroepen van de volgende vraag ook de vorige ("sender") meeneemt, kan je ook een stack opbouwen voor het teruglopen door de lijst.

[ Voor 27% gewijzigd door Reptile209 op 27-01-2011 16:44 ]

Zo scherp als een voetbal!


Acties:
  • 0 Henk 'm!

  • Tony L
  • Registratie: September 2005
  • Laatst online: 07-11-2015
Reptile209 schreef op donderdag 27 januari 2011 @ 16:42:
Als je nu bij *iedere* vraag *alle* antwoorden voorziet van een NextQuestionNumber-eigenschap. Bij simpele vragen is dat stomweg het volgende vraagnummer, maar daar waar routering (volgens mij heet het zo in questionaires) van belang is kan je verschillende paden gaan definieren. Zo werken (hardcopy)belastingformulieren e.d. eigenlijk ook: "ga verder met vraag 4c".
Dat is zeker mogelijk! Ik denk alleen dat je veel problemen kan krijgen met vragenlijsten die nooit compleet zijn in te vullen.

Voorbeeld:
code:
1
2
3
4
5
6
7
1. Hou je van worst?
- Ja (Ga naar 2)
- Nee (Ga naar 2)

2. Hou je van bloemkool?
- Ja (Ga naar 1)
- Nee (Ga naar 1)


En het lijkt me ook niet zo heel simpel om een algoritme te gaan schrijven die kan bepalen of de vragenlijst überhaupt wel ingevuld kan worden. Volgens mij is dat zelfs een Halting Problem ;)
quote: Wikipedia
In computability theory, the halting problem is a decision problem which can be stated as follows: Given a description of a program, decide whether the program finishes running or continues to run, and will thereby run forever. This is equivalent to the problem of deciding, given a program and an input, whether the program will eventually halt when run with that input, or will run forever.
Reptile209 schreef op donderdag 27 januari 2011 @ 16:42:
En als je dan bij het aanroepen van de volgende vraag ook de vorige ("sender") meeneemt, kan je ook een stack opbouwen voor het teruglopen door de lijst.
Dat laatste volg ik niet helemaal. Ik hou nu een stack bij binnen de Survey echter doe ik niets met een "sender". Op het moment dat de vraag beantwoord is gooi ik hem in de stack en kan op die manier simpel terug lopen. Maar misschien dat ik niet goed volg waarom een "sender" handig zou kunnen zijn.


Kleine update heren, onwijs bedankt voor alle feedback!! Ik heb het probleem van subquestion's getackeled. Ik laat de Survey zelf bepalen wat de volgende vraag gaat worden. Dit doe ik nu met een recursieve functie, dus qua onderhoud valt het allemaal wel mee! Het enige wat ik nu nog moet inbouwen is het conditionele verhaal, echter het moeilijkste heb ik zojuist opgelost >:)

Ik realiseerd me echter weer een moeilijkheidje... Stel dat je conditionele paden hebt, en je bouwt een "geschiedenis" op van wat er allemaal is ingevuld. Dan geldt die geschiedenis natuurlijk alleen op het moment dat je niets veranderd in de vragenlijst zelf.

Voorbeeldje:
code:
1
2
3
1. A
1.1 B (Omdat vraag 1 met A is beantwoord komt deze vraag erbij)
1.2 C (Omdat vraag 1 met A is beantwoord komt deze vraag erbij)


Stel dat ik helemaal terug ga naar het begin van de vragenlijst, en ik vul "B" in bij vraag 1, dan moet ik eigenlijk de gehele geschiedenis boven vraag 1 in zijn geheel verwijderen? Ik vraag me alleen af of dit wel de juiste denkwijze is. Het kan zijn dat alleen vraag 1 conditioneel is en de rest niet, dan heb ik mooi al die vragen ook direct uit de geschiedenis verwijderd. Beetje raar lijkt me. Ik wil het niet te complex maken maar hoe ga ik überhaupt uitvogelen dat een bepaalde vraag invloed heeft op het verloop van de vragenlijst? Hoe kan ik op voorhand weten dat vraag 5.C een andere tree oplevert dan 5.D? En hoe zorg ik er voor dat ik de overlap van de twee tree's behoudt zonder alles gewoon weg te gooien?

Ik krijg een donkerbruin vermoeden dat ik het weer veel te complex wil maken ;)

PSN: Norfirin


Acties:
  • 0 Henk 'm!

  • barfieldmv
  • Registratie: Maart 2004
  • Laatst online: 23-08 21:37
Ik zou een lijst van vragen maken. Elke vraag heeft een eigen unieke ID en een lijstje van unieke ID's is dan een geschiedenis.

Conditionele vragen hebben een 'conditie' eigenschap. Aan de hand van een conditie eigenschap word een vraag of geskipped of gesteld.
Multiple answer vragen hebben een 'vervolg vraag' die ook dynamisch is. Aan de hand van een conditie eigenschap word de volgende vraag gekozen.

[ Voor 21% gewijzigd door barfieldmv op 28-01-2011 19:46 ]


Acties:
  • 0 Henk 'm!

  • Guldan
  • Registratie: Juli 2002
  • Laatst online: 11:30

Guldan

Thee-Nerd

Ik heb een keer implementatie gezien waar het volgende gebeurde:

Je hebt de volgende tabellen: vragen/antwoorden/formulieren. In de programma logica werd aan een bepaald formulier een soort van controle/flow logica toegevoegd bij het tonen die bijv vragen niet zichtbaar liet zijn etc. Deze was gewoon geimplementeerd in code en werd d.m.v een interface gemakkelijk gekoppeld aan het formulier.

You know, I used to think it was awful that life was so unfair. Then I thought, wouldn't it be much worse if life were fair, and all the terrible things that happen to us come because we actually deserve them?

Pagina: 1