Hash doesn't print in Perl - perl

I have a hash:
while( my( $key, $value ) = each %sorted_features ){
print "$key: $value\n";
}
but I cannot obtain the correct value for $value. It gives me:
intron: ARRAY(0x3430440)
source: ARRAY(0x34303b0)
exon: ARRAY(0x34303f8)
sig_peptide: ARRAY(0x33f0a48)
mat_peptide: ARRAY(0x3430008)
Why is it?

Your values are array references. You need to do something like
while( my( $key, $value ) = each %sorted_features ) {
print "$key: #$value\n";
}
In other words, dereference the reference. If you are unsure what your data looks like, a good idea is to use the Data::Dumper module:
use Data::Dumper;
print Dumper \%sorted_features;
You will see something like:
$VAR1 = {
'intron' => [
1,
2,
3
]
};
Where { denotes the start of a hash reference, and [ an array reference.

You can use also Data::Dumper::Pertidy which runs the output of Data::Dump through Perltidy.
#!/usr/bin/perl -w
use strict;
use Data::Dumper::Perltidy;
my $data = [{title=>'This is a test header'},{data_range=>
[0,0,3, 9]},{format => 'bold' }];
print Dumper $data;
Prints:
$VAR1 = [
{ 'title' => 'This is a test header' },
{ 'data_range' => [ 0, 0, 3, 9 ] },
{ 'format' => 'bold' }
];

Your hash values are array references. You need to write additional code to display the contents of these arrays, but if you are just debugging then it is probably simpler to use Data::Dumper like this
use Data::Dumper;
$Data::Dumper::Useqq = 1;
print Dumper \%sorted_features;
And, by the way, the name %sorted_features of your hash worries me. hashes are inherently unsorted, and the order that each retrieves the elements is essentially random.

Related

Can I pass mix type of optional arguments to a subroutine?

I am trying to pass a hash and optional list of variables to a subroutine in hash but its not working. Could you please correct below sample code to help me with the approach?
My sample code looks like
#!/bin/env perl
use warnings;
use strict;
use Data::Dumper;
my %h1 = ( a=> 2, b=>3);
sub sum {
my $var1=shift;
my $var2=shift;
my %hash1=#_;
#my($a,$b)=#_;
my $i=0;
foreach my $val (keys %hash1) {
$i=$i+$hash1{$val};
}
if ( not defined $var2 ) {
return ($i+$var1);
} else {
return ($i+$var1+$var2);
}
}
my $c=sum(3,%h1);
print $c;
You call your subroutine like this:
my $c=sum(3,%h1);
And inside your subroutine, you access the parameters like this:
my $var1=shift;
my $var2=shift;
my %hash1=#_;
There seems to be an obvious discrepancy here. You're passing a scalar and a hash to the subroutine, but inside your subroutine, you're expecting two scalars and a hash.
So perhaps it will work as you expect it to if you remove the my $var2 = shift line.
It's not really clear what your subroutine is meant to do. If you were to explain that, then we could probably be a little more help.
Update: You have Data::Dumper in your code. Why not use it to try to understand what is going on.
print Dumper(\#_), "\n";
my $var1=shift;
my $var2=shift;
my %hash1=#_;
print Dumper($var1, $var2, \%hash1), "\n";
I get:
$VAR1 = [
3,
'b',
3,
'a',
2
];
Odd number of elements in hash assignment at test line 11.
$VAR1 = 3;
$VAR2 = 'b';
$VAR3 = {
'3' => 'a',
'2' => undef
};
Which shows a couple of interesting things:
The hash being "unrolled" into a list before being put into #_.
The warning you get when you initialise a hash from a list with an odd number of elements.
Your %hash1 variable with incorrect keys and values.
Thanks everyone. This is how we can pass optional arguments to a subroutine in perl with type mixed
#!/bin/env perl
use warnings;
use strict;
use Data::Dumper;
my %h1 = ( a=> 2, b=>3);
sub sum {
my ($hash1,$var1,$var2)=#_;
#my($a,$b)=#_;
my $i=0;
foreach my $val (keys %{$hash1}) {
$i=$i+$hash1->{$val};
}
if (defined $var2 ) {
return ($i+$var1+$var2);
} else {
return ($i+$var1);
}
}
my $c=sum(\%h1,3);
print $c;
Please correct me if I missed something.
Regards,
Divesh
#!/usr/bin/perl
use warnings;
use strict;
use JSON;
use feature qw(say);
args_in( 'test', { foo => 'bar' }, ["one", "two", "three"] );
sub args_in {
my $args_aref = parse_args( #_ );
say to_json $args_aref;
}
sub parse_args {
my #ary;
foreach( #_ ) {
my %hash;
if (ref $_) {
$hash{type} = ref $_;
} else {
$hash{type} = 'SCALAR';
}
$hash{value} = $_;
push #ary, \%hash;
}
return \#ary;
}
Results:
[
{
"value": "test",
"type": "SCALAR"
},
{
"value": {
"foo": "bar"
},
"type": "HASH"
},
{
"value": [
"one",
"two",
"three"
],
"type": "ARRAY"
}
]

Accessing and modifying a nested hash based on a dot separated string

I have a string as input, say apple.mango.orange = 100
I also have a hash reference:
$inst = {
'banana' => 2,
'guava' => 3,
'apple' => {
'mango' => {
'orange' => 80
}
}
};
I want to modify the value of orange using the input string. Can someone please help me how I could do this?
I tried splitting the string into (key, value) pair. I then did the following on the key string:
my $key2 = "\$inst->{".$key."}";
$key2 =~ s/\./}->{/g;
$$key2 = $value;
This does not work as intended. Can someone help me out here? I have read the Perl FAQ about not using a variable value as variable but I am unable to think of an alternative.
You are building string that consists of (buggy) Perl code, but you never ask Perl to execute it. ...but that's not the right approach.
sub dive_val :lvalue {
my $p = \shift;
$p = \($$p->{$_}) for #_;
$$p
}
my #key = split /\./, "apple.mango.orange";
dive_val($inst, #key) = $value;
or
use Data::Diver qw( DiveVal );
my #key = split /\./, "apple.mango.orange";
DiveVal($inst, map \$_, #key) = $value;
Not only is a symbolic reference a very bad idea here, it doesn't even solve your problem. You're building an expression in $key2, and just jamming another dollar sign in front of its name won't make perl execute that code. For that you would need eval, which is another bad idea
You can install and use the Data::Diver module, which does exactly this sort of thing, or you can simply loop over the list of hash keys, picking up a new hash reference each time and assigning the value to the element with the last key
The biggest issue is actually parsing the incoming string into a list of keys and a value. This code implements a subroutine apply which applies the implied operation in the string to a nested hash. Unless you are confident of your data, it needs some error checking addingto make sure each of the keys in the list exists. The Data:;Dumper output is just to demonstrate the validity of the result
use strict;
use warnings 'all';
use Data::Dumper;
my $inst = { 'banana' => 2, 'guava' => 3, 'apple' => { 'mango' => { 'orange' => 80 } } };
my $s = 'apple.mango.orange = 100';
apply($s, $inst);
print Dumper $inst;
sub apply {
my ($operation, $data) = #_;
my ($keys, $val) = $operation =~ /([\w.]+)\s*=\s*(\d+)/;
my #keys = split /\./, $keys;
my $last = pop #keys;
my $hash = $data;
$hash = $hash->{$_} for #keys;
$hash->{$last} = $val;
}
output
$VAR1 = {
'banana' => 2,
'apple' => {
'mango' => {
'orange' => '100'
}
},
'guava' => 3
};

Perl: overwrite structure member value

I am creating $input with this code:
push(#{$input->{$step}},$time);, then I save it in an xml file, and at the next compiling, I read it from that file. When i print it, i get the structure bellow.
if(-e $file)
my $input =XMLin($file...);
print Dumper $input;
and I get this structure
$VAR1 = {
'opt' => {
'step820' => '0',
'step190' => '0',
'step124' => '0',
}
};
for each step with it's time..
push(#{$input->{$step}},$time3);
XmlOut($file, $input);
If I run the program again, I get this structure:
$VAR1 = {
'opt' => {
'step820' => '0',
'step190' => '0',
'step124' => '0',
'opt' => {
'step820' => '0',
'step190' => '0',
'step124' => '0'
}
}
I just need to overwrite the values of steps(ex:$var1->opt->step820 = 2). How can i do that?
I just need to overwrite the values of steps(ex:$var1->opt->step820 = 2). How can i do that?
$input->{opt}->{step820} = 2;
I'm going to say what I always do, whenever someone posts something asking about XML::Simple - and that is that XML::Simple is deceitful - it isn't simple at all.
Why is XML::Simple "Discouraged"?
So - in your example:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
my $xml= XML::Twig->new->parsefile($file);
$xml -> get_xpath('./opt/step820',0)->set_text("2");
$xml -> print;
The problem is that XML::Simple is only any good for parsing the type of XML that you didn't really need XML for in the first place.
For more simple examples - have you considered using JSON for serialisation? As it more directly reflects the hash/array structure of native perl data types.
That way you can instead:
print {$output_fh} to_json ( $myconfig, {pretty=>1} );
And read it back in:
my $myconfig = from_json ( do { local $/; <$input_fh> });
Something like:
#!/usr/bin/env perl
use strict;
use warnings;
use JSON;
my $input;
my $time = 0;
foreach my $step ( qw ( step820 step190 step124 ) ) {
push(#{$input->{$step}},$time);
}
print to_json ( $input, {pretty=>1} );
Giving resultant JSON of:
{
"step190" : [
0
],
"step820" : [
0
],
"step124" : [
0
]
}
Although actually, I'd probably:
foreach my $step ( qw ( step820 step190 step124 ) ) {
$input->{$step} = $time;
}
print to_json ( $input, {pretty=>1} );
Which gives;
{
"step190" : 0,
"step124" : 0,
"step820" : 0
}
JSON uses very similar conventions to perl - in that {} denote key value pairs (hashes) and [] denote arrays.
Look at the RootName option of XMLout. By default, when "XMLout()" generates XML, the root element will be named 'opt'. This option allows you to specify an alternative name.
Specifying either undef or the empty string for the RootName option will produce XML with no root elements.

How can I flatten the arguments to my subroutine into an array?

Consider following script:
use strict;
use Data::Dumper;
my #arr=('1A','2A');
my $arr_ref=['1','2'];
sub routine1
{
my #arr=#_;
print Dumper(\#arr);
}
routine1(#arr,'one_A');
sub routine2
{
my $arr_ref=[#_];
print Dumper($arr_ref);
}
routine2($arr_ref,'one');
routine1 is using #arr and routine2 is using $arr_ref.
routine1 prints the following:
$VAR1 = [
'1A',
'2A',
'one_A'
];
routine2 prints following:
$VAR1 = [
[
'1',
'2'
],
'one'
];
I want to continue using #_ and arr_ref in routine2 but want to come up with below output:
$VAR1 = [
'1',
'2'
'one'
];
Can someone suggest the way out?
Using the function ref you can see if a scalar is a reference (and if so, which type). In a simplistic case where only array references will be passed you can simply use this to flatten the inputs.
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
sub test {
my #arr = map { ref() ? #$_ : $_ } #_;
print Dumper \#arr;
}
test( ['a', 'b'], 1 );
As a side benefit, this code will die with a message if a reference to another type is passed, since you attempt to deference as an array. If you need to handle more, you will need to check the reference type. This starts to build in complexity quickly.
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
sub test {
my #arr = map {
my $type = ref;
if ( ! $type ) {
$_;
} elsif ( $type eq 'ARRAY' ) {
#$_;
} elsif ( $type eq 'HASH' ) {
%$_;
} else {
()
}
} #_;
print Dumper \#arr;
}
test( ['a', 'b'], { p => 'q' }, 1 );
By returning an empty list for other reference types I silently ignore all other reference types. Or perhaps you would rather force stringification on other reference types.
...
} else {
"$_";
}
...
test( ['a','b'], sub{}, bless({},'MyClass'), 1 );
Of couse which of these handlings to use depends on you use case.
Just wrote this the other day at work.
sub flatten {
return map { ref($_) ? flatten(#{$_}) : ($_) } #_;
}
This program shows a subroutine flatten that will flatten a mixed list of simple data and array references, nested to any level.
use strict;
use warnings;
use Data::Dump;
my #arr = qw/ 1A 2A /;
my $arr_ref = [1, 2];
sub flatten;
routine1(#arr, 'one_A');
routine2($arr_ref, 'one');
sub routine1 {
my #arr=#_;
dd \#arr;
}
sub routine2 {
my $arr_ref = [flatten #_];
dd $arr_ref;
}
sub flatten {
my $i = 0;
while ($i < #_) {
my $item = $_[$i];
if (ref $item eq 'ARRAY') {
splice #_, $i, 1, #$item;
}
else {
++$i;
}
}
#_;
}
output
["1A", "2A", "one_A"]
[1, 2, "one"]

Traversing the hash of hash of array

Here is by code :
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my $var = {
Cars => {
cars_name => [
"GT500",
"Beetle",
"P1800"
]
},
Bikes => {
Bikes_name => [
"Pulsar",
"Discover",
"CBR"
]
}
};
#Traversing the hash of hash of array
print "$var\n";
foreach my $k1 (keys %{$var}) {
print "$k1\n";
print $var->$k1;
#foreach my $k2 (keys %{$var->$k1}) {
#print"$k2\n";
#}
}
Whenever i am trying to print cars_name and Bikes_name , i am getting an error message saying the Can't call method Cars on Unblessed reference. I am not able to figure it out where am i doing mistake. Well, by mine understanding this print $var->$k1; line creating a prob. So please can any body help me out of this.
Thanks
print $var->$k1;
that is calling a method on an object. You want to access a hash:
print $var->{$k1};