Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
973 views
in Technique[技术] by (71.8m points)

perl - Odd number of elements in hash assignment with default

Greeting Dear Community.

I'm trying to make a sub in perl that takes a hash and a debug flag which defaults to zero. However I keep getting this error Odd number of elements in hash assignment. If I don't use the debug flag, it seems to work.

Thanks for all the help.

Code:

#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
use POSIX qw(strftime);


#
#file2hash : read the file in k<file_name> e.g.=kconfig &  kmem  into hash table
#

sub file2hash {
    my ($file) = @_;

open(my $data, '<', $file) or die "Could not open '$file' $!
";

my %HoH;
my $key;
my $value;
my $who;
my $rec;
my $field;

#while ( my $line = <$data>) {
while ( <$data>) {
    #print $line;
    next unless (s/^(.*?):s*//); # / turn off editor coloring
    $who = $1;
    #print $who;
    $rec = {};
    $HoH{$who} = $rec;
    for $field ( split ) {
        ($key, $value) = split /=/, $field;
        $rec->{$key} = $value;
    }
}

    return %HoH;

}
#
#end file2hash
#


#
#print out hash table in k<file_name> format
#
sub hash2print{
    (my %HoH,my $debug) = @_;
    #my ($debug)=@_||0;
    #my %HoH = shift;
    #my $debug = shift || 0;

    my $family;
    my $role;

    for $family ( keys %HoH ) {
        #print "$family
";
        for $role ( keys %{ $HoH{$family} } ) {
             if ($debug){
                print "family:$family
";
                print "role: $role
";
             }
             print "$role=$HoH{$family}{$role}";

        }
        print "
";
    }
}
#
#end hash2print
#

sub dispatch{

        my $inc= shift;
        my $config_f = shift || "kconfig";
        my $memory_f = shift || "kmem";

        my %h2=&file2hash($config_f);
        my %m2=file2hash($memory_f);

        my $today=&getDate();

        print "$today
";
        print "$inc
";
        my $inc_cnt = $m2{$today}{$inc} || -999999999;
        print "$inc_cnt
";

        #my %config = shift;
        #my %mem = shift;
        #my $event = shift;
        #print $m2{$inc}{$today};
}

sub getDate{
my $date = strftime "%m/%d/%Y", localtime;  # "
#print $date;
return $date;
}

my %h2=&file2hash("kconfig");
my %m2=&file2hash("kmem");
&hash2print(%h2,1);
&hash2print(%m2,1);
#print &getDate();
#my $xcnt= &dispatch("event_c3_z2");
#&dispatch("event_c3_z2");
#print $xcnt;

Test file1:

event_a1_x1: email1=ackee0000@gmail.com email2=kym018@gmail.com email1_cnt=6
event_a1_x2: email1=ackee0000@gmail.com email2=kym018@gmail.com email1_cnt=5 
event_b2_y1: email1=ackee0000@gmail.com email2=kym018@gmail.com email1_cnt=4 
event_b2_y2: email1=ackee0000@gmail.com email2=kym018@gmail.com email1_cnt=3 
event_c3_z1: email1=ackee0000@gmail.com email2=kym018@gmail.com email1_cnt=2 
event_c3_z2: email1=ackee0000@gmail.com email2=kym018@gmail.com email1_cnt=1

test file2:

201609230012: event_a1_x1=6
201609230744: event_a1_x2=5
201609230844: event_b2_y1=4
201609230342: event_b2_y2=3
201609230245: event_c3_z1=2
201609230100: event_c3_z2=1
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Arguments are passed to a function as one flat list. On the other hand, a hash can be assigned a list, %h = qw(a b), where consecutive elements form key-value pairs, $h{a} is 'b'. So when a hash is the first variable that receives arguments in a function it scoops up all of them. Here is a recent post on how a function returns, where the exact same story applies.

So everything is assigned to the hash, the remaining scalar as well. Thus the hash gets one more element than intended and ends up with an odd number of elements.

A solution -- in this case, only to pass hash by reference, as in the answer by Inferno

sub hash2print{
    my ($rHoH, $debug) = @_;
    my %HoH = %$rHoH;
    # ...
}
hash2print(\%h2, 1);

It is in principle a good idea to pass lists by reference, unless they are very short.

In general you can pass the scalar first then the hash

sub hash2print{
    my ($value, %HoH) = @_;
    # ...
}
hash2print(1, %h2);

But in your case this doesn't go since the $debug is optional, and if we leave it out when calling the function the first key of the hash would wind up in $value.

A few other comments

  • Don't use globals unless there is a non-negotiable reason for that. Declare in small scope.

  • You don't have to do $rec = {};, can just declare it my $rec;.

  • In general, don't put & in front of a function call but use just file2hash(...);


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...