Reputation: 2498
I have the following text file.
foo1 bam
foo1 bam
foo2 bam
foo1 zip
foo2 boo
foo1 zip
foo3 zip
I would like to make a Hash of Hashes where KEY1 is column one, KEY2 is the sound it makes (column two): bam
, zip
, or boo
, and the VALUE is the number of occurrences of that sound. Such that the data structure is like this:
$VAR1 = {
'foo1' => {
'bam' => [
2
],
'zip' => [
2
],
},
'foo2' => {
'bam' => [
1
],
'boo' => [
1
],
},
'foo3' => {
'zip' => [
1
],
}
}
Here's what I have so far
use strict; use warnings;
open(my $fh, '<', 'file.txt') or die $!;
my %HoH;
while(<$fh>){
chomp;
my @cols = split(/\t/, $_);
my $KEY1 = $cols[0];
my $KEY2 = $cols[1];
push( @{$HoH{$KEY1}{$KEY2}}, 1); # This actually creates a hash of hash of arrays
}
my %HoH_final;
foreach my $KEY1 (%HoH) {
foreach my $KEY2 (keys %HoH{$KEY1}){
my $count = scalar @{$HoH{$KEY1}{$KEY2}}; # get the size of that array
push( @{$HoH_final{$KEY1}{$KEY2}}, $count);
}
}
What do you think?
Upvotes: 4
Views: 316
Reputation: 26121
Actually this will do the trick
perl -F'\t' -ane'$h{$F[0]}{$F[1]}++'
If you want see the result
perl -MData::Dumper -F'\t' -ane'$h{$F[0]}{$F[1]}++}{print Dumper(\%h)'
Upvotes: 3
Reputation: 385887
Don't you actually want the following data structure?
{
'foo1' => {
'bam' => 2,
'zip' => 2,
},
...
}
If so,
while (<$fh>) {
chomp;
my @cols = split /\t/;
++$HoH{ $cols[0] }{ $cols[1] };
}
If you really want the one-element arrays,
while (<$fh>) {
chomp;
my @cols = split /\t/;
++$HoH{ $cols[0] }{ $cols[1] }[0];
}
Upvotes: 5
Reputation: 66978
Is there a reason why each second-level key points to an arrayref instead of the number? I'd recommend doing it like this:
while(<$fh>){
chomp;
my @cols = split(/\t/, $_);
$HoH{ $cols[0] }{ $cols[1] }++;
}
That will increment (++
) the value at each second-level key when it is encountered.
Upvotes: 3