Building hash of hashes?

5 views
Skip to first unread message

Otto J. Makela

unread,
Aug 27, 2021, 9:59:45 AMAug 27
to
The following demo builds a counter (using a hash of hashes) into
memory from the DATA section and then displays the result. However,
I'm not terribly fond of the way I create the hashes in the hash.

This demo of course is a simplification of my actual use case,
where I ended up having three-layered hashes embedded with
complex initialization.

Does anyone have suggestions for a "neater" way to do this?

----

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

# Collect DATA into hash of hashes
my %data;
while(<DATA>) {
chomp;
(my $a, my $b) = split(/\s+/,$_,2);
if(defined $data{$a}) {
$data{$a}{$b}++;
} else {
$data{$a} = { $b => 1 };
}
}

# Print out collected data
foreach my $a (sort keys %data) {
print $a;
foreach my $b (sort keys $data{$a}) {
print "\t",$b,"\t",$data{$a}{$b},"\n";
}
}

__DATA__
yy cc
xx aa
yy aa
yy bb
xx cc
zz cc
yy bb
xx bb
yy aa

--
/* * * Otto J. Makela <o...@iki.fi> * * * * * * * * * */
/* Phone: +358 40 765 5772, ICBM: N 60 10' E 24 55' */
/* Mail: Mechelininkatu 26 B 27, FI-00100 Helsinki */
/* * * Computers Rule 01001111 01001011 * * * * * * */

AnonymousCoward

unread,
Aug 27, 2021, 5:07:36 PMAug 27
to

How about:

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

# Collect DATA into hash of hashes
my %data;
while(my $l = <DATA>) {
chomp $l;
(my $a, my $b) = split(/\s+/,$l,2);
$data{$a}{$b}++;
}

# Print out collected data
while (my ($a, $d) = each %data) {
print $a;
print "\t$_\t@{[$d->{$_}]}\n" for (sort keys %$d);

Otto J. Makela

unread,
Aug 30, 2021, 8:39:45 AMAug 30
to
AnonymousCoward <anon...@coward.com> wrote:

> How about:
...
> (my $a, my $b) = split(/\s+/,$l,2);
> $data{$a}{$b}++;

Okay, this was actually what I felt was the ugliest bit:
I wasn't aware that anonymous hashes would automatically
get instantiated into the hash. Thus the convolutions I
went to manually build them were quite unnecessary.

I've learnt a new thing here, thank you!

George Bouras

unread,
Sep 1, 2021, 4:18:48 AMSep 1
to
#!/bin/perl
use strict;
use warnings;

# Collect DATA into hash of hashes
my %data;
while (<DATA>) {
$data{$1}->{$2}++ if /^(\S+)\s+(.*?)\s*$/
}

use Data::Dumper; print Dumper \%data;

Randal L. Schwartz

unread,
Sep 2, 2021, 9:03:11 PMSep 2
to
>>>>> "Otto" == Otto J Makela <o...@iki.fi> writes:

Otto> Okay, this was actually what I felt was the ugliest bit:
Otto> I wasn't aware that anonymous hashes would automatically
Otto> get instantiated into the hash. Thus the convolutions I
Otto> went to manually build them were quite unnecessary.

Yes, thanks to the loved/hated feature of autovivification.

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<mer...@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Dart/Flutter consulting, Technical writing, Comedy, etc. etc.
Still trying to think of something clever for the fourth line of this .sig

Otto J. Makela

unread,
Sep 6, 2021, 9:58:39 AMSep 6
to
George Bouras <f...@example.com> wrote:

> $data{$1}->{$2}++ if /^(\S+)\s+(.*?)\s*$/

This works just as well even without the explicitly written ->

My actual use case was significantly more convoluted,
with three levels of indirection, this was just a simplification.

George Bouras

unread,
Sep 6, 2021, 4:47:36 PMSep 6
to
> My actual use case was significantly more convoluted,
> with three levels of indirection, this was just a simplification.
>
no problem if you want more help
Reply all
Reply to author
Forward
0 new messages