### making presence/absence table from a hash of arrays

by reubs85 (Acolyte)
 on Sep 05, 2011 at 18:21 UTC Need Help??
reubs85 has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

Please impart some Perl wisdom to a poor and pitiful Monkling...

Allow me to paint a simplistic picture of my conundrum: I have an array with (for arguments sake) 5 elements, thus:

one two three four five

And I have a hash where the keys are row numbers and the values are references to an array; this array having a varying number of elements that are equal to the headers in the table, but not necessarily in the same order, like so:

```row_1 = one five two
row_2 = four two
row_3 = three one five four
etc...

What I would dearly like is to print a table where each cell is filled with a 1/0 presence/absence binary, depending on if the column header in question is present in the array, thus for the hypothetical example above, we would get:

```one two three four five
row_1 = 1 1 0 0 1
row_2 = 0 1 0 1 0
row_3 = 1 0 1 1 1
etc...

Any tips or pointers would be massively appreciated,

Thanks very much!

Replies are listed 'Best First'.
Re: making presence/absence table from a hash of arrays
by jwkrahn (Monsignor) on Sep 05, 2011 at 19:58 UTC
```\$ perl -le'
my @array = qw/ one two three four five /;
my %hash  = (
row_1 => [ qw/ one five two / ],
row_2 => [ qw/ four two / ],
row_3 => [ qw/ three one five four / ],
);

print "@array";

for my \$key ( sort keys %hash ) {
print "\$key = ", join " ", map { my \$elem = \$_; grep( \$_ eq \$elem,
+ @{ \$hash{ \$key } } ) ? 1 : 0 } @array;
}
'
one two three four five
row_1 = 1 1 0 0 1
row_2 = 0 1 0 1 0
row_3 = 1 0 1 1 1

The grep can be simplified with a smart match:

```for my \$key (sort keys %hash) {
say "\$key = ", join ' ', map \$_ ~~ \$hash{\$key} ? 1 : 0, @array;
}
Re: making presence/absence table from a hash of arrays
by Anonymous Monk on Sep 05, 2011 at 18:33 UTC

Hi

If you a hash and an array, why are you posting a word question (ie homework)?

Thanks for the responses everyone,

Incidentally, it is not 'homework'; I am a PhD genome biologist still getting to grips with the finer details of Perl - I am going to use the code as part of a script that will allow me to count genes which are shared across different species. The example I wrote was merely for ease of readership.

So whilst its true that I should learn more about the grep and map functions (although asking questions is part of learning, I think), I'm not skipping my way through some homework assignment.

Thanks again!

It is certainly possible to get a lot done without fancy map statements. There is certainly something to be said for doing something straightforward with foreach loops. Don't worry about being compact/terse - do something that is easy for you to understand - worry about more complex constructs when you are writing a lot more Perl.

See code below. Perl is great at translating one thing into another thing - the hash table. So I just make a hash table table to translate the column name into an array index. This also perhaps could have been just statically declared, but I wanted to make this flexible. For each row in the table, I just zero out an array and use the name2Index translator to turn on the appropriate elements and then print that row.

```#!/usr/bin/perl -w
use strict;
use Data::Dump qw(pp);

my \$header_row= 'one two three four five';
my %table = (  row_1 => [qw(one five two)],
row_2 => [qw(four two)],
row_3 => [qw(three one five four)],
);

my %name2Index;

my \$col=0;
{
}

print "name2Index table = ",pp(\%name2Index),"\n\n";

foreach my \$row (sort keys %table)
{
my @bitmap = (0) x keys %name2Index;

foreach my \$col_name (@{\$table{\$row}})
{
\$bitmap[\$name2Index{\$col_name}] = 1;
}

print "\$row = @bitmap\n";
}

__END__
name2Index table = { five => 4, four => 3, one => 0, three => 2, two =
+> 1 }

row_1 = 1 1 0 0 1
row_2 = 0 1 0 1 0
row_3 = 1 0 1 1 1
Re: making presence/absence table from a hash of arrays
by Anonymous Monk on Sep 06, 2011 at 09:39 UTC

You clearly want to use a regular expression:

```#!/ichigo/perl

use v5.12;
use warnings;
use strict;

my @array = qw/ one two three four five /;
my %hash  = (
row_1 => [ qw/ one five two / ],
row_2 => [ qw/ four two / ],
row_3 => [ qw/ three one five four / ],
);

my \$row = "@array";
say \$row;

for my \$key (sort keys %hash) {
my \$re = join '|', @{\$hash{\$key}};
say "\$key = ", grep s/\b(\$re)\b|\w+/\$#-/g, "\$row";
}

Create A New User
Node Status?
node history
Node Type: perlquestion [id://924283]
Approved by planetscape
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (5)
As of 2018-06-23 10:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
Should cpanminus be part of the standard Perl release?

Results (125 votes). Check out past polls.

Notices?