in reply to help with 2D arrays with perl requested

Anonymonk:

I know you've specified a 2D matrix, but in this case, I think a hash would be simpler. Think of the hash as a sparse array. Something like this:

#!/usr/bin/perl -w use warnings; use strict; my @animals = ("cat", "dog", "fish", "horse", "pig"); my %count; while (<DATA>) { my ($x,$y) = split /\s/; ($x,$y) = ($y,$x) if ($x gt $y); $count{$x}{$y}++; } for my $x (sort keys %count) { for my $y (sort keys %{$count{$x}}) { print $count{$x}{$y}," people have both a ", $x, " and a ", $y, "\n"; } } __DATA__ cat dog cat fish pig dog horse fish pig fish dog fish fish cat
--roboticus

Replies are listed 'Best First'.
Re^2: help with 2D arrays with perl requested
by roboticus (Chancellor) on Apr 29, 2006 at 12:53 UTC
    ...and here's the 2D array method I tried. You can see why I prefer the hash, as it's a good bit more involved, since you need to map the animal names into array indices. Take out the lines that start with "next" and you'll see another reason I prefer the hash.

    And now for the code....

    #!/usr/bin/perl -w use warnings; use strict; my @animals = ("cat", "dog", "fish", "horse", "pig"); # Hash to map an animal to an array index. I'm sure there's a # better way, but I don't know it... my %a2i; my $i=0; for my $a (@animals) { $a2i{$a}=$i++; } my @count; while (<DATA>) { my ($x,$y) = split /\s/; ($x,$y) = ($y,$x) if ($x gt $y); $count[$a2i{$x}][$a2i{$y}]++; } for my $x (sort keys %a2i) { next if !defined $count[$a2i{$x}]; for my $y (sort keys %a2i) { next if !defined $count[$a2i{$x}][$a2i{$y}]; print $count[$a2i{$x}][$a2i{$y}], " people have both a ", $x, " and a ", $y, "\n"; } } __DATA__ cat dog cat fish pig dog horse fish pig fish dog fish fish cat
    --roboticus
      Wouldn't this accomplish the task more simply?
      #!/usr/bin/perl -w use warnings; use strict; my %count; while (<DATA>) { chomp; my ($x,$y) = split /\s/; ($x,$y) = ($y,$x) if ($x gt $y); $count{"$x $y"}++; } foreach (sort keys %count) { print "people with $_: $count{$_}\n"; } __DATA__ cat dog cat fish pig dog horse fish pig fish dog fish fish cat
        ruzam:

        Thanks! That tip will certainly come in handy. Collapsing both keys into one certainly saves a bit of effort.

        Major Update: Someone downvoted this, and I suspect that it's because they thought I was sarcastic or because I didn't mention *why* I thought it would save effort. So I'll elaborate a little: In my array version, I had to use those "next if !defined" bits to prevent error messages from printing. By collapsing both keys into one, all those error checks disappear from the code. So the net improvement is: We remove an inner loop (for *each* use!) and we remove the "next" statements (again, for *each* use).

        Expecting another downvote at any time now..... 8^)

        --roboticus

      Thank you very much. I really appreciate your help

      just out of interest - in your opinion - how difficult might it be to convert the results into a graphical form? I was thinking something along the lines of a matrix with squares filled in at the appropriate places?

        You could convert it to graphical form very easily. In that case, I'd use the 2D array form, and then in the printout loop, generate the contents of each square based on its value.

        For ASCII graphics, you could set thresholds for different counts, such as ' ' for no animals, '.' for 1-2, ':' for 3-6, '*' for 7-15 and '#' for 15+ or some such. If you wanted HTML, you could do basically the same thing, just generate your table cells with something like:

        <td bgcolor="xxxxxx">&nbsp;</td>
        filling in the appropriate background color based on the number of critter matches.

        --roboticus