Have an idea?

Visit Sawtooth Software Feedback to share your ideas on how we can improve our products.

Using tables to randomly display options to user (with constraints)

Hello everybody,

Let's see if I am able to describe correctly what I'm trying to implement: I need to present to the user a list of 4 different random options each time, from a total of 10. The problem is, I want to do it with constraints, just like in a MaxDiff exercise. Ideally, it would appear just like a MaxDiff exercise (tables with the options), but without the check boxes, since the answers will be given by a slider (the table would be used only to display the options, and not to collect data). Does anyone know if there is an "easy" way to do this in SSI Web?

By the way, I'm using version 7.0.26.

Best regards,
João Fernandes
asked Mar 21, 2012 by João Fernandes Bronze (2,040 points)
edited Mar 21, 2012 by João Fernandes

2 Answers

0 votes
 
Best answer
Here is the updated "easy" solution:

First go to lists and enter your 10 items in that list, call that list "listItems" (case sensitive)
Then create another predefined list called "Combinations" and enter all the possible combinations there, if you have no constraints, you would have 210 combinations (combin 4 of 10). If you need help with that you can use the macro here to create the combinations in Excel (http://pastebin.com/8a4xndJi) Remove the ones that are constrained and then enter "," in between them
Your Combinations list should look like
1,2,3,4
1,2,3,5
1,2,3,6
1,2,3,7
1,2,3,8
1,2,3,9


Now create a constructed list and enter the following code:
Begin Unverified Perl
    my $randNum=0;
    my $tmpString = "";
    my @tmpItems = ();
    $randNum=SYSRAND(1,210);
    $tmpString = LISTLABEL("Combinations",$randNum);
    @tmpItems = split(',', $tmpString);
    ADD("listItems",$tmpItems[0]);
    ADD("listItems",$tmpItems[1]);
    ADD("listItems",$tmpItems[2]);
    ADD("listItems",$tmpItems[3]);
    RANDOMIZE();
End Unverified

change the 210 above to whatever combinations were left after your removal of constrained lines.
use the constructed list in your question and you'll end up showing the 4 items from a random line in the combinations list.


Earlier suggestion:
I'd use merged variables to add a predefined rotation number to the respondents (you can also do sysrand as Paul suggested in a recent thread).
Then I'd define all my possible rotations (taking the constraints into account) in a parent list. Finally, I'd use the random notation to build a constructed list I want to use for the respondent.

I hope I could express it in these sentences :)

Important notice: I have realized that SYSRAND generates the same output for the same second in time... If two respondents reach this piece of code at the same time, they will end up with the same lists.
answered Mar 21, 2012 by Bahadir Ozkurt Gold (16,930 points)
edited May 4, 2012 by Bahadir Ozkurt
I've been buried in a project for the past few days. I've thought of another, perhaps simpler approach.
I'll have something ready for you on Monday latest :)
scroll up and find my updated answer. It should save you time and headache with Perl :)
Thanks, I will now look deeply at your answer. I've already seen it, but I've been learning and messing up with Perl, and haven't got the time to explore it ;]
added a notice about sysrand
I was aware of that, but I thought it was combined with the system's date (day/month/year), so I thought it was a unique sequence of random numbers. I will evaluate if this detail somehow affects the survey, thanks!
+1 vote
I made myself a little script in Perl to generate all the combinations wanted. The first version prints all the possible combinations, without constraints:

#!/usr/bin/perl
use strict;
use warnings;

use Algorithm::Combinatorics qw(combinations);

my @data = qw(1 2 3 4 5 6 7 8 9 10);
my $k = 4;

open(my $output, ">", "combinations_all.txt") or die "Can't open combinations_all.txt: $!";

my $iter = combinations(\@data, $k);

while (my $combination = $iter->next)
{
    print "@$combination\n";
    print $output "@$combination\n";
}

close $output or die "$output: $!";
answered Mar 29, 2012 by João Fernandes Bronze (2,040 points)
have you checked my updated answer? it's much easier :)
But then I thought it was going to be likely to accidentally delete combinations while selecting them, so I made a safer and faster way of automatically select them (taking constraints in account). This avoids human errors (I tested it with my own constraints and it worked), but if you find any error please let me know.

Here it goes:

#!/usr/bin/perl
use strict;
use warnings;

use Algorithm::Combinatorics qw(combinations);

my @data = qw(1 2 3 4 5 6 7 8 9 10); # items numeration
my $k = 4; # combinations of k (out of the number of items of @data)

open(my $output, ">", "combinations.txt") or die "Can't open combinations.txt: $!";

my $iter = combinations(\@data, $k);

my @constraints = ([1, 2],
           [3, 4],
           [4, 5],
           [6, 7],
           [7, 8],
           [9, 10]); # array of constraints
       
my $aref = 0;
my $boolean = 0;

while (my $combination = $iter->next)
{    
    for $aref (@constraints)
    {    
        if(!contain_constraints(@$aref, @$combination)) # sends combination + defined constraints
        {
            $boolean=0; # FALSE
        }
        else
        {
            $boolean=1; # TRUE
            last; # if it does contain a constraint, walks out of the loop
        }
    }
    
    if($boolean==0) # if it doesn't contain any of the defined constraints, then prints to the screen and to file
    {
        print "@$combination\n";
        print $output "@$combination\n";
    }
}

close $output or die "$output: $!";

sub contain_constraints # method to take constraints in account
{    
    my (@const) = @_[0..1];
    my (@comb) = @_[2..$#_];
    
    my $comb_str = "@comb";
    my $const_str = "@const";
    
    if ($comb_str =~ $const_str)
    {
        return 1;
    }
    
    return 0;
}
using perl just to create the list from a predefined set of possible values seemed a rather easy way to solve your problem. To be honest I didn't expect you to take so deep a dive into Perl :)
Sometime I would have to learn it, so I used this chance to do it ;] I'm still having doubts, this time in SSI Web: when you mention "use the constructed list in your question and you'll end up showing the 4 items from a random line in the combinations list.", how do you use the list? Since I'm not using a MaxDiff question, I don't have access to the "Items" tab (I'm using a free format question, since I do not want to use the check boxes, only show a table with the questions). I guess I'm missing something, what can possible be?
you mentioned that you only want to show the items from a list next to some sliders...
<table>
  <tr>
    <td>
      [%ListLabel(ConstructedListName,1)%]
    </td>
  </tr>  <tr>
    <td>
      [%ListLabel(ConstructedListName,2)%]
    </td>
  </tr>  <tr>
    <td>
      [%ListLabel(ConstructedListName,3)%]
    </td>
  </tr>  <tr>
    <td>
      [%ListLabel(ConstructedListName,4)%]
    </td>
  </tr>
</table>

should allow you to use the items in a neat table
I've been trying to work this out. When I use something like

<table border="1" width="800px">
    <tr>
        <td>
            [%ListLabel(RandomQuestions,1)%]
        </td>
    </tr>
    <tr>
        <td>
            [%ListLabel(RandomQuestions,2)%]
        </td>
    </tr>
    <tr>
        <td>
            [%ListLabel(RandomQuestions,3)%]
        </td>
    </tr>
    <tr>
        <td>
            [%ListLabel(RandomQuestions,4)%]
        </td>
    </tr>
</table>


it outputs something like this:

1 3 6 10
1 3 7 9
1 3 5 10
1 3 5 7

(which is weird, since I've tested split() in a separated .pl file and it worked well)

And if I use the code this way:

<table border="1" width="800px">
    <tr>
        <td>
            [%ListLabel(ListItems,1)%]
        </td>
    </tr>
    <tr>
        <td>
            [%ListLabel(ListItems,2)%]
        </td>
    </tr>
    <tr>
        <td>
            [%ListLabel(ListItems,3)%]
        </td>
    </tr>
    <tr>
        <td>
            [%ListLabel(ListItems,4)%]
        </td>
    </tr>
</table>


It does indeed output my items (although without constraints). So, I'm doing something wrong, I just don't know what...

My "Combinations" list is something like:

"1 3 5 6
1 3 5 7
(...)"

"listItems" is another list (the one with the actual items), and "RandomQuestions" is my constructed list (the parental one being "Combinations"):

Begin Unverified Perl
    my $randNum=0;
    my $tmpString = "";
    my @tmpItems = ();
    $randNum=SYSRAND(1,69);
    $tmpString = LISTLABEL("Combinations", $randNum);
    @tmpItems = split(" ", $tmpString);
    ADD("listItems",$tmpItems[0]);
    ADD("listItems",$tmpItems[1]);
    ADD("listItems",$tmpItems[2]);
    ADD("listItems",$tmpItems[3]);
    RANDOMIZE();
End Unverified
you mind sending your .ssi to ozkurt at gmaildotcom?
So, the problem I was having in the last post of the previous answer is now solved.

Basically, the constructed list ("RandomQuestions") was the key to it. It should have "ListItems" as the parental list (not "Combinations", as I had previously posted), and the correct code in the "Variables / Question HTML" tab of the free format question should  be the first I posted before:

<table border="1" width="800px">
    <tr>
        <td>
            [%ListLabel(RandomQuestions,1)%]
        </td>
    </tr>
    <tr>
        <td>
            [%ListLabel(RandomQuestions,2)%]
        </td>
    </tr>
    <tr>
        <td>
            [%ListLabel(RandomQuestions,3)%]
        </td>
    </tr>
    <tr>
        <td>
            [%ListLabel(RandomQuestions,4)%]
        </td>
    </tr>
</table>
...