newbio has asked for the wisdom of the Perl Monks concerning the following question:

Hi fellow Monks,

I have a task at hand. Being a beginner, I don't have much idea how to approach this problem. Please enlighten me as to how I can do this in Perl.

Given are,

a) Two sets of variables, say First: {A,B,C..} and Second: {X}, where A,B,C and X are all categorical variables, for example, A can take any number of values such as 0,1,2..etc. Same is the case for other variables. For simplicity, consider that all categorical values in each variable starts from 0.

b) Number of variables present in the first set namely, {A,B,C..} may change, ie it can have any number of variables.

c) First set {A,B,C} is ordered within itself, say A corresponds to 0, B corresponds to 1, C corresponds to 2 and X corresponds to 4. The number assigned to X is always more than the numbers assigned to variables in the first set.

Thus for a particular case, we are given First and Second sets with possible values each variable can take.

Task: Design a function that returns a tabular output something like this (assuming two values each in the four variables, although in reality there can be many more variables, each containing any number of values):

A B C X 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 1 0 1 0 0 0 1 0 1 0 1 1 0 0 1 1 1 1 0 0 0 1 0 0 1 1 0 1 0 1 0 1 1 1 1 0 0 1 1 0 1 1 1 1 0 1 1 1 1

Please note, the number of rows in the table is the product of all values the variables can take. The table essentially is an ordered listing of all possible combinations of values of the variables in First and Second sets. The order is such that the innermost column is looped fastest (column X in this case) followed by C, B and finally A (A being slowest). Each column count starts with 0 and increases as as we move down the table, until all values of that variable are exhausted (see table). We also see that the ordering of variables defined in c) is maintained in this tabular output. The table, thus, enumerates all possible combinations of values of variables in an ordered way.

Thanks a lot, Raj

Replies are listed 'Best First'.
Re: How to do?
by bart (Canon) on Oct 22, 2004 at 11:03 UTC
    I think all you need is a binary counter, like this:
    $vars = 4; # number of bits for my $i (0 .. (1<<$vars)-1) { printf "%0${vars}b\n", $i; }
    Well, you might want to spread the cell entries a little, so you'll have fun figuring that out. :)

    As for the header: you can cheat. All you have to do is sort the names in order of value, and print them out first. Above the table the code here creates.

    And $vars in the above code must be the same as your number of variables. More beginners' fun.

Re: Dynamically assigning number of for loops?
by tilly (Archbishop) on Oct 22, 2004 at 18:41 UTC
    You don't say how your code is supposed to get those values. Let's say for the sake of argument that it is something like this:
    my %to_combine = ( A => "0,1", B => "0,1", C => "0,1", X => "0,1", ); # Then the following prints it out... print join " ", sort keys %to_combine; print "\n"; my $s = join "\\ ", map "{$to_combine{$_}}", sort keys %to_combine; print "$_\n" for glob $s;
      Terrific, Thanks a lot guys! You guys make problem look so simple which otherwise look invincible to me. Great!

      Tilly, well your hash %to_combine is something that will be passed to the function as you have correctly shown. You have used a function "glob" which seems to work ideally for this job. Could you please elaborate how this function works. I tried checking about this function on google, but in most places it says "glob" is used for finding files/directories, such as *.pl etc. Please tell how it is doing the magic in the present context.

      Hail Monks! Raj

        I was looking back and realized that I never answered this.

        The glob function produces a list of filename expansions in such a way as to mimic how /bin/csh does filename expansions on Unix. The manpage for csh in "Filename substitution" explains the metanotation that I took advantage of to make this give you something other than filenames.

Re: Dynamically assigning number of for loops?
by Random_Walk (Prior) on Oct 22, 2004 at 15:39 UTC

    Here is a little something allowing you to enter the number of ABC colums and to specify min and max values (ie 0 and 1, 0 and 9, a and z)

    #!/usr/local/bin/perl -w use strict; print "enter number of columns:"; chomp (my $ow_many=<>); my $min="f"; my $max="h"; my @array; $array[$_-1]=$min for 1..$ow_many; my $i=0; while ($i <= $ow_many) { my $x=""; for (@array) {$x=$_ if $_ gt $x} print join " ", @array, " $x\n"; $i=0; my $carry=1; while ($carry) { if (defined $array[$i] && $array[$i] eq $max) { $array[$i]=$min; }else{ $carry--; $array[$i]++; } $i++; } }

    Cheers,
    R.

Re: Dynamically assigning number of for loops? (cheat)
by tye (Sage) on Oct 22, 2004 at 16:24 UTC

    You could use Algorithm::Loops for this, but that would probably get you a poor grade. You could search for that name and find some discussions about how it works (and probably some other ways of doing this type of thing). If it starts to make sense, then you could read the source code and see how it works.

    - tye        

Re: How to do?
by rdfield (Priest) on Oct 22, 2004 at 10:49 UTC
    We're not big on answering homework questions here. Try Google.

    rdfield

Re: How to do?
by rjbs (Pilgrim) on Oct 22, 2004 at 12:20 UTC
    Although "we don't do homework" might fill many of them, you'd get more replies with a subject better than "how to do?"

    If the subject line doesn't explain the subject of the node, many monks will ignore it and move on to another.
    rjbs
Re: Dynamically assigning number of for loops?
by ww (Archbishop) on Oct 22, 2004 at 16:27 UTC
    I'm not clear whether the words or the table better convey(s) your intent:

    "The number assigned to X is always more than the numbers assigned to variables in the first set."

    but lines 0, 2, 3, 4 & 5 (inter alia) do not appear to satisfy the quoted rule. (By some chance, is the table you provided merely like "greek type" -- a filler that shows layout before actual content is available?)
Re: Dynamically assigning number of for loops?
by newbio (Beadle) on Oct 22, 2004 at 12:49 UTC
    Thanks guys, for your suggestions. I used google but did not get the answer. Well, this is not part of homework or anything. I am just on self learning..:)

    I thought of solving it but couldn't arrive at a solution. The problem is that the number of variables in "First Set" may change from one case to the other, and my function should work for all such cases. I tried to use "for loops", but they wouldn't work because the number of "for loops" may change from cases to case, depending on the number of variables "First Set" has.

    I am asking for suggestions rather than the code to solve this problem. This way I can write and test code myself and thereby learn more.

    Cheers, Raj

Re: Dynamically assigning number of for loops?
by TedPride (Priest) on Oct 22, 2004 at 14:48 UTC
    for (<DATA>) { chomp; split(/ => /); $hash{$_[0]} = $_[1]; } $data[$#data+1] = [split(/ /, $hash{$_})] for (sort keys %hash); print join("\t", sort keys %hash) . "\n"; for (0..(1<<$#data+1)-1) { $bin = sprintf("%0".($#data+1)."b", $_); for (0..$#data) { print $data[$_][substr($bin,$_,1)]."\t" } print "\n"; } __DATA__ A => 0 1 B => 2 3 C => 4 5 X => 6 7