thudzj has asked for the wisdom of the Perl Monks concerning the following question:

I use hash of hashes and maybe many layer of hashes,and I often run into the error message like in my title! now I have some codes as follows

#!/bin/perl -w use strict; my $site_file=$ARGV[0]; #input the methylation site info my %site_info=(); open(IN_site,"<$site_file"); while(<IN_site>) { chomp; my @arr=split(/\t/,$_,4); if($arr[0] eq "MULTI"){next;} my @chr_temp=split //,$arr[0]; for(1..3) { shift(@chr_temp); } $arr[0]=join("",@chr_temp); $site_info{$arr[0]}{$arr[1]}{"strand"}=$arr[2]; $site_info{$arr[0]{$arr[1]}}{"value"}=$arr[3]; } close IN_site;

i try to use hashes of hashes of hashes to input my $site_flie, and the all the lines have the formats as follows:

chr16 28797601 - 0.777877

I use a lot of there kinds of hashes and this kind of problem often happens,please help me!

Thanks in advance!

I do not want remove use strick

Replies are listed 'Best First'.
Re: Can't use string ("16") as a HASH ref while "strict refs" in use
by CountZero (Bishop) on Jun 30, 2012 at 08:12 UTC
    The whole of
    my @chr_temp=split //,$arr[0]; for(1..3) { shift(@chr_temp); } $arr[0]=join("",@chr_temp);
    can be replaced by:
    $arr[0] = substr($arr[0], 3);
    Now as to our problem: Are you sure, there isn't a typo in
    $site_info{$arr[0]{$arr[1]}}{"value"}=$arr[3];
    and you really meant
    $site_info{$arr[0]}{$arr[1]}{"value"}=$arr[3];

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

    My blog: Imperial Deltronics

      Thanks a lot! I checked it several times to find it out! This is a stupid mistake!

Re: Can't use string ("16") as a HASH ref while "strict refs" in use
by AnomalousMonk (Archbishop) on Jun 30, 2012 at 12:21 UTC

    As CountZero has suggested, the error can be exactly duplicated in the presence of the likely typo:

    >perl -wMstrict -le "$_ = qq{chr16\t28797601\t-\t0.777877}; my %site_info; ;; my @arr = split(/\t/,$_,4); $arr[0] = substr($arr[0], 3); $site_info{$arr[0]}{$arr[1]}{'strand'} = $arr[2]; $site_info{$arr[0]{$arr[1]}}{'value'} = $arr[3]; " Can't use string ("16") as a HASH ref while "strict refs" in use at .. +.

    And goes away and is replaced by something reasonable with the 'fixed' code:

    >perl -wMstrict -le "use Data::Dump qw(dd); ;; $_ = qq{chr16\t28797601\t-\t0.777877}; my %site_info; ;; my @arr = split(/\t/,$_,4); $arr[0] = substr($arr[0], 3); $site_info{$arr[0]}{$arr[1]}{'strand'} = $arr[2]; $site_info{$arr[0]}{$arr[1]}{'value'} = $arr[3]; ;; dd \%site_info; " { 16 => { 28797601 => { strand => "-", value => 0.777877 } } }

    Sometimes it's useful to introduce a temoprary 'convenience' variable in place of complex nested expressions:

    >perl -wMstrict -le "use Data::Dump qw(dd); ;; $_ = qq{chr16\t28797601\t-\t0.777877}; my %site_info; ;; my @arr = split(/\t/,$_,4); $arr[0] = substr($arr[0], 3); ;; my $current = $site_info{$arr[0]}{$arr[1]} = {}; $current->{'strand'} = $arr[2]; $current->{'value'} = $arr[3]; ;; dd \%site_info; " { 16 => { 28797601 => { strand => "-", value => 0.777877 } } }

    Or to use slicing to do multiple, 'simultaneous' assignment:

    >perl -wMstrict -le "use Data::Dump qw(dd); ;; $_ = qq{chr16\t28797601\t-\t0.777877}; my %site_info; ;; my @arr = split(/\t/,$_,4); $arr[0] = substr($arr[0], 3); ;; @{ $site_info{$arr[0]}{$arr[1]} }{ qw(strand value) } = @arr[2, 3]; ;; dd \%site_info; " { 16 => { 28797601 => { strand => "-", value => 0.777877 } } }

      Thanks a lot! Thought I got a stupid mistake,your suggestion is really helpful for my coding on hashes.

Re: Can't use string ("16") as a HASH ref while "strict refs" in use
by Marshall (Canon) on Jun 30, 2012 at 13:33 UTC
    The code seems overly complex to me.
    There are some steps:
    a) parse the input lines and assign values to some variables.
    b) Use those variables to create the data structure.

    The below could be a way to parse the data.
    A HoHoH is a pretty complex data structure. What are you trying to do? There might be some better alternatives, but I don't know enough to comment on that. Can you explain more about your objective?

    #!usr/bin/perl -w use strict; my %site_info=(); while (<DATA>) { next if /^\s*MULTI/; #skip MULTI lines next if /^\s*$/; #skip blank lines # default split is /\s+/ which includes # all of the whitespace charaters [ \n\r\f\t] # From the data shown (no spaces within the # tokens), why not just split on simple whitespace? my ($chrStr, $strand, $value) = (split)[0,1,3]; # ditch the dash # use simple regex to get the "chr number" my ($chrNum) = $chrStr =~ /(\d+)/; #just get the digits.. print "$chrNum $strand $value\n"; } =prints 16 28797601 0.777877 32 887755 0.11 =cut __DATA__ chr16 28797601 - 0.777877 MULTI some stuff chr32 887755 - 0.11