HASH(0x1970c80) in Perl script - perl

I have the following code:
#!/usr/bin/perl
use warnings;
use strict;
my $count;
my #chomp;
my $length;
my %hash;
my $orf;
open FILE, "<", $ARGV[0];
while ( my $line = <FILE> ) {
if ( $line =~ /LOCUS/ ) {
$count++;
$line =~ s/ +/\t/g;
#chomp = split( /\t/, $line );
$length = $chomp[2];
$hash{$count}->{length} = $length;
}
elsif ( $line =~ /misc_feature (\w+)\.\.(\w+)/ ) {
$orf = $2 - $1;
if ( !defined $hash{$count}->{orf} or $hash{$count}->{orf} < $orf ) {
$hash{$count}->{orf} = $orf;
}
}
}
for my $key (%hash) {
print $key. "\n";
# print $hash{$key}->{"orf"}."\t".$hash{$key}->{"length"}."\n";
}
that gives the following output:
HASH(0x140ae60)
13891
HASH(0x18d4060)
5056
HASH(0x15c4968)
15612
HASH(0x1970c80)
18787
HASH(0x1a98448)
7684
I do not understand why is it? It should print $count value (for example 1, 2, 3...). In fact, it is printed, but with that HASH(0x over there.

You should use
for my $key (keys %hash)
{ ... }

You need to deference since it's a hash of hashes:
use warnings;
use strict;
for my $length (keys %hash) {
print "$length\n";
for my $count (keys %{$hash{$length}}) {
print "$count\n";
}
}

That's because you're building a hash-of-hashes:
$hash{$count}->{length} = $length;
when you print out $hash{whatever}, you're trying to print out that "inner" hash, which is where your HASH(0xXXXXXXX) output it coming from.

for my $key (keys %hash) {
print $key."\n";
# print $hash{$key}->{"orf"}."\t".$hash{$key}->{"length"}."\n";
}

As many others says, you need to use keys if you want get the keys. So:
for my $key (keys %hash)
^^^^
here
the full example:
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my %hash = (
cnt13 => {
'length' => 'len13'
},
'cnt12' => {
'orf' => 'orf12',
'length' => 'len12'
},
'cnt11' => {
'length' => 'len11'
},
'cnt10' => {
'orf' => 'orf10',
'length' => 'len10'
}
);
for my $key (keys %hash) {
say "key is CNT: $key";
for my $subkey (keys %{$hash{$key}} ) {
say "\tGot a subkey: $subkey with a value: $hash{$key}->{$subkey}";
}
}
say Dumper \%hash;
prints:
key is CNT: cnt11
Got a subkey: length with a value: len11
key is CNT: cnt13
Got a subkey: length with a value: len13
key is CNT: cnt12
Got a subkey: orf with a value: orf12
Got a subkey: length with a value: len12
key is CNT: cnt10
Got a subkey: length with a value: len10
Got a subkey: orf with a value: orf10
$VAR1 = {
'cnt11' => {
'length' => 'len11'
},
'cnt13' => {
'length' => 'len13'
},
'cnt12' => {
'orf' => 'orf12',
'length' => 'len12'
},
'cnt10' => {
'length' => 'len10',
'orf' => 'orf10'
}
};

Related

Print the value in Hash of Hash for two different keys in Perl

Below is a hash in Perl:
my %hash = (
'episode1' => {
'when' => '08.13.97',
'airdate' => '08.13.97',
'episodenumber' => '101',
'id' => '103511',
'title' => 'Cartman Gets an Anal Probe',
'available' => 'true'
},
'episode2' => {
'when' => '08.20.97',
'airdate' => '08.20.97',
'episodenumber' => '102',
'id' => '1035156',
'title' => 'Weight Gain 4000',
'available' => 'true'
}
);
I want to print the "id" of both episodes,but the below code is not working:
foreach my $key1 ( keys %hash ) {
foreach my $key2 ( keys %{$hash{$key1}} ) {
print "$hash{$key1}{$key2}{id}\n";
}
}
Please help.
The problem is that you're trying to print something that doesn't exist: There is no value that matches $hash{$key1}{$key2}{id}.
Try this code, which prints out the value in the hash of hashes that has the key "id":
use strict;
use warnings;
for my $episode (keys %hash){
print "$hash{$episode}{id}\n";
}
103511
1035156
Try using map:
my #ids = map { $hash{$_}{"id"} } sort keys %hash;
Or if you still need the results as a hash:
my %ids_by_key = map { ($_, $hash{$_}{"id"}) } keys %hash;
Try this:
foreach my $key1 ( keys %hash ) {
print "$hash{$key1}{id}\n";
}
or
foreach my $key1 ( keys %hash ) {
foreach my $key2 ( keys %{$hash{$key1}} ) {
print "$hash{$key1}{$key2}\n" if($key2 eq 'id');
}
}

Converting HoA to HoH with counting

Have this code:
use 5.020;
use warnings;
use Data::Dumper;
my %h = (
k1 => [qw(aa1 aa2 aa1)],
k2 => [qw(ab1 ab2 ab3)],
k3 => [qw(ac1 ac1 ac1)],
);
my %h2;
for my $k (keys %h) {
$h2{$k}{$_}++ for (#{$h{$k}});
}
say Dumper \%h2;
produces:
$VAR1 = {
'k1' => {
'aa2' => 1,
'aa1' => 2
},
'k3' => {
'ac1' => 3
},
'k2' => {
'ab1' => 1,
'ab3' => 1,
'ab2' => 1
}
};
Is possible to write the above code with "another way"? (e.g. simpler or more compact)?
Honestly, I don't like the number of times $h2{$k} is evaluated.
my %h2;
for my $k (keys %h) {
my $src = $h{$k};
my $dst = $h2{$k} = {};
++$dst->{$_} for #$src;
}
A subroutine can help make the intent more obvious. Maybe.
sub counts { my %c; ++$c{$_} for #_; \%c }
$h2{$_} = counts(#{ $h{$_} }) for keys %h;
That can be simplified if you do the change in-place.
sub counts { my %c; ++$c{$_} for #_; \%c }
$_ = counts(#$_) for values %h;

Perl: Sorting hash of hash by value descending order

data :
%HoH => (
abc => {
value => "12",
},
xyz => {
number => "100",
},
pqr => {
digit => "5",
}
)
How do I sort the hash of hash by value in descending order?
Output
100
12
5
You can't sort a hash, it won't hold the order. If you wanted to keep them sorted, you'll have to sort the keys based on the number and store the keys in an array.
#!/usr/bin/perl
use strict;
use warnings;
my %HoH = (
abc => { value => 12 },
xyz => { value => 100},
pqr => { value => 5},
def => { value => 15},
hij => { value => 30},
);
my #sorted_keys = map { $_->[0] }
sort { $b->[1] <=> $a->[1] } # use numeric comparison
map { my $temp;
if ( exists $HoH{$_}{'value'} ) {
$temp = $HoH{$_}{'value'};
} elsif ( exists $HoH{$_}{'number'} ) {
$temp = $HoH{$_}{'number'};
} elsif ( exists $HoH{$_}{'digit'} ) {
$temp = $HoH{$_}{'digit'};
} else {
$temp = 0;
}
{[$_, $temp]} }
(keys %HoH);
for my $key (#sorted_keys) {
my $temp;
if ( exists $HoH{$key}{'value'} ) {
$temp = $HoH{$key}{'value'};
} elsif ( exists $HoH{$key}{'number'} ) {
$temp = $HoH{$key}{'number'};
} elsif ( exists $HoH{$key}{'digit'} ) {
$temp = $HoH{$key}{'digit'};
} else {
$temp = 0;
}
print $key . ":" . $temp ."\n";
}
Output:
xyz:100
hij:30
def:15
abc:12
pqr:5
This technique to do the sorting is called Schwartzian Transform.
Given you're not actually using the keys for anything, you can flatten the data structure into a single array and then sort it:
use strict;
use warnings;
my %HoH = (
abc => {value => "12",},
xyz => {number => "100",},
pqr => {digit => "5",},
);
my #numbers = sort {$b <=> $a} map {values %$_} values %HoH;
print "$_\n" for #numbers;
Outputs:
100
12
5
However, if you want to use the additional key information, then you'll need fold your Hash of Hash into an array, and then you can sort however you like:
my #array;
while (my ($k, $ref) = each %HoH) {
while (my ($k2, $v) = each %$ref) {
push #array, [$k, $k2, $v];
}
}
#array = sort {$b->[2] <=> $a->[2]} #array;
use Data::Dump;
dd \#array;
Outputs:
[
["xyz", "number", 100],
["abc", "value", 12],
["pqr", "digit", 5],
]
I came up with this solution
#!/usr/bin/perl
use strict;
use warnings;
my %HoH = (
abc => {
value => "12",
},
xyz => {
number => "100",
},
pqr => {
digit => "5",
}
);
my %rever;
for my $TopKey(keys %HoH){
for my $value(values %{ $HoH{$TopKey} }){
push #{ $rever{$value} }, $TopKey;
}
}
my #nums = sort {$b <=> $a} (keys(%rever));
print $_, "\n" for #nums;
I reversed the values in case you still needed to use the key names.
This is how it looks after using Dumper.
$VAR1 = '100';
$VAR2 = [
'xyz'
];
$VAR3 = '12';
$VAR4 = [
'abc'
];
$VAR5 = '5';
$VAR6 = [
'pqr'
];

Getting values from a hash by order defined in another list

Looking for a way, how to get the values from a hash, in an order defined by another list.
The "demo" code (real values are different):
use 5.014;
use warnings;
my $href = {
'Long one' => 'v1',
'xxx two' => 'v2',
'another3' => 'v3',
'xfour' => 'v4',
'some5' => undef,
};
#keys from the $href in defined order
my #order = ('Long one', 'xfour', 'nono', 'another3', 'some5', 'xxx two');
#in the real code:
#my $href = some_sub(......); my #order = another_sub(....);
#cleanup the #order form undefined values
#order = grep { exists $href->{$_} && defined $href->{$_} } #order;
#my input
while(<DATA>) {
chomp;
#filter out nonexistent keys and undefined values
my #defined_data = grep { exists $href->{$_} && defined $href->{$_} } split '/';
my $str = "xx";
$str = join('/',
map { $href->{$_} } some_my_sort(#defined_data)
) if #defined_data;
say $str;
}
sub some_my_sort {
my(#list) = #_;
# "somewhat"sort the #list in order defined by #order
# haven't any idea how to do this :(
# __HERE NEED HELP__ to sort the #list, to the order defined in the #order
#and get only first two values. if exists only one value, return only one
if($#list > 0) {
return ($list[0], $list[1]);
}
else {
return($list[0]);
}
}
__DATA__
another3/some5/Long one/xfour/xxx two
xxx two/blabla/some5/another3/xfour
some5
notexists/some5/xxx two/Long one
some5/another3
for the above input want get the next output:
v1/v4
v4/v3
xx
v1/v2
v3
Form #ikegami solution:
use 5.014;
use warnings;
my $href = { 'Long one' => 'v1', 'xxx two' => 'v2', 'another3' => 'v3', 'xfour' => 'v4', 'some5' => undef, };
my #order = ('Long one', 'xfour', 'nono', 'another3', 'some5', 'xxx two');
#order = grep { exists $href->{$_} && defined $href->{$_} } #order;
my %order = map { $order{$_} => $_ } 0..$#order;
while (<DATA>) {
chomp;
my #keys = grep { defined $href->{$_} } split '/';
#keys = sort { $order{$a} <=> $order{$b} } #keys;
splice(#keys, 2) if #keys > 2;
#keys = 'xx' if !#keys;
say join '/', #{$href}{ #keys };
}
get the next - error - and don't really understand why:
Global symbol "%order" requires explicit package name at ike line 8.
Execution of ike aborted due to compilation errors.
After defining #order, define %order_h:
my %order_h;
my $i = 0;
$order_h{$_} = $i++ for #order;
Then, instead of the comment about sorting, add this line:
#list = sort { $order_h{$a} <=> $order_h{$b} } #list;
Here's a cleaned-up version of the entire code:
my %order = map { $order[$_] => $_ } 0..$#order;
while (<DATA>) {
chomp;
my #keys = grep { defined $href->{$_} } split '/';
#keys = sort { $order{$a} <=> $order{$b} } #keys;
splice(#keys, 2) if #keys > 2;
say join '/', #keys ? #{$href}{ #keys } : 'xx';
}

How do I sort hash of hashes by value using perl?

I have this code
use strict;
use warnings;
my %hash;
$hash{'1'}= {'Make' => 'Toyota','Color' => 'Red',};
$hash{'2'}= {'Make' => 'Ford','Color' => 'Blue',};
$hash{'3'}= {'Make' => 'Honda','Color' => 'Yellow',};
foreach my $key (keys %hash){
my $a = $hash{$key}{'Make'};
my $b = $hash{$key}{'Color'};
print "$a $b\n";
}
And this out put:
Toyota Red Honda Yellow Ford Blue
Need help sorting it by Make.
#!/usr/bin/perl
use strict;
use warnings;
my %hash = (
1 => { Make => 'Toyota', Color => 'Red', },
2 => { Make => 'Ford', Color => 'Blue', },
3 => { Make => 'Honda', Color => 'Yellow', },
);
# if you still need the keys...
foreach my $key ( #
sort { $hash{$a}->{Make} cmp $hash{$b}->{Make} } #
keys %hash
)
{
my $value = $hash{$key};
printf( "%s %s\n", $value->{Make}, $value->{Color} );
}
# if you don't...
foreach my $value ( #
sort { $a->{Make} cmp $b->{Make} } #
values %hash
)
{
printf( "%s %s\n", $value->{Make}, $value->{Color} );
}
print "$_->{Make} $_->{Color}" for
sort {
$b->{Make} cmp $a->{Make}
} values %hash;
plusplus is right... an array of hashrefs is likely a better choice of data structure. It's more scalable too; add more cars with push:
my #cars = (
{ make => 'Toyota', Color => 'Red' },
{ make => 'Ford' , Color => 'Blue' },
{ make => 'Honda' , Color => 'Yellow' },
);
foreach my $car ( sort { $a->{make} cmp $b->{make} } #cars ) {
foreach my $attribute ( keys %{ $car } ) {
print $attribute, ' : ', $car->{$attribute}, "\n";
}
}