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

I am trying to setup a hash from an array to sort out
related data. I am very much a newbie to perl. I have
a semicolon delimeted file that looks somewhat like this:

Mac PPC;43
Client for Windows NT 4.0;204
(goes on for about 30 lines)

I have that data placed into an array (@calarray) and would like to get the two fields into a hash. I have been unsuccessful so far. My code is:
my @calarray; #puts data to @calarray like I want it to while (<OUTFILE>) { push (@calarray, $_); } my $key = ""; my $value = ""; #This is what I'm having trouble with. %sorting = map { my ($key, $value1) = split ";"; $key => $value } @calarray; print "$key, $value";
I have tried multiple other solutions with no luck. I am a newbie, trying to learn perl on my own so I apologize if this is a dumb question. Any thoughts or info is greatly appreciated... Thanks, Ben

Replies are listed 'Best First'.
Re: How to assign a hash from an array?
by guha (Priest) on Mar 10, 2002 at 18:57 UTC

    You could enter the data directly into a hash, below is an example which seem to match the approach you have been trying.

    use strict; my %calhash; while (<OUTFILE>) { # Should be <INFILE> ?? chomp; my ($value, $key) = split(/;/, $_); $calhash{$key} = $value; }

    Of course this requires that you are guaranteed that there is only one semicolon in each line. Otherwise you will have to use a regexp.

    ---
    I would like to change the world but God won't let me have the source code.
Re: How to assign a hash from an array?
by seattlejohn (Deacon) on Mar 10, 2002 at 19:23 UTC
    You've basically got it -- there are just two minor problems that are preventing you from getting the result you want. Inside your map, you name a variable $value1 in the split statement, but then use $value (not $value1) on the next line. If you used the same name, the assignment would work properly.

    Also, using my inside the map means that you are declaring local versions of $key and $value that are different than the $key and $value you declare above, so you can't access them once you've left the map. You could replace your print statement with something like this, though:
    print "$_ => $sorting{$_}\n" foreach keys %sorting;

    (which will print all the information in the hash)

Re: How to assign a hash from an array?
by particle (Vicar) on Mar 10, 2002 at 20:07 UTC
    i suggest you use warnings; or #!perl -w which would have caught your re-declaration of the $key variable, and your declaration of $value1 without using it (you probably meant $value.)

    otherwise, your use of map is correct. but you also seem to be confused about variable scoping. in that case, Coping with scoping (or anything on Dominus's home node) may be a good read.

    it's good practice, during development, to put the following block in every perl script:

    #!/usr/local/bin/perl -w use strict; use diagnostics; $|++;
    of course, you'll replace '/usr/local/bin/perl' with the location of your perl executable. this will turn on the warnings, strict, and diagnostics pragmas, which will enforce some good coding practices, and make code easier to debug. for more info, read Use strict warnings and diagnostics or die. also, $|++ will unbuffer your output to STDOUT, which means printing will be timely.

    ~Particle ;Þ

(jeffa) Re: How to assign a hash from an array?
by jeffa (Bishop) on Mar 10, 2002 at 20:08 UTC
    Ok, let's say that @calarray (not a good name by the way, very easy to type it wrong) has alreay been populated, and populated with tainted user input to make things icky:
    my @line = qw(foo;bar baz;qux user;errors;suck trust; ;no-one ;);
    You can use this snippet to only get those items that have one token before the first semi-colon, and also one token after that semi-colon:
    my %hash = grep !/^$/, map { ($a,$b) = $_ =~ /^([^;]+);([^;]+)/; ($a,$b); } @line;
    I chose not to worry about possible whitespace, it is ugly enough as it is. The idea is to do as guha rightfully said, use a regex. The map filters out the key and value pairs, but because of tainted user input, we still get an undefined key (actually, three candidates that overwrite each other). The grep takes care of those.

    Warning: I use $a and $b in this example. These variables are meant to be used with sort, but i see no problem in using them here - you don't even have to declare them. Just don't be tempted to use them for any task more than temporary. In fact, you should probably just stick to only using them for sort. ;)

    Also, a time saving tip: If you want to quickly see if the hash (or array or any other data strucure) contains what you think it should, use Data::Dumper (thanks to guha for clearing up my blunder - see below ;))

    use Data::Dumper; print Dumper \@array; print Dumper \%hash; print Dumper $reference;
    From the first two code snippets, the variable %hash should look like:
    $VAR1 = {
              'foo' => 'bar',
              'baz' => 'qux',
              'user' => 'errors'
            };
    

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      use Data::Dumper;

      print \@array;
      print \%hash;
      print $reference;

      Won't work.

      You'll need to type
      use Data::Dumper; print Dumper(\%hash);

      Furthermore recent postings have indicated that use of the special variables for sort, $a and $b, gets in the way of DWIM and should best be avoided for general use.

      ---
      I would like to change the world but God won't let me have the source code.
        Thanks for bringing the Dumper error to my attention.

        Now, as for $a and $b - i did already give a warning about them. However, i feel that in this case - it's ok to use them. I never declared them, see the difference? Those recent postings you refer to declare $a and $b as lexical variables.

        If you disagree, then please show me how my example would 'get in the way of DWIM'.

        Thanks again. :)

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        B--B--B--B--B--B--B--B--
        H---H---H---H---H---H---
        (the triplet paradiddle with high-hat)
        
Re: How to assign a hash from an array?
by Juerd (Abbot) on Mar 10, 2002 at 18:36 UTC

    my %hash = map { chomp; split /;/, $_, 2 } <OUTFILE>;

    I leave decoding of the above as an exercise.

    44696420796F7520732F2F2F65206F
    7220756E7061636B3F202F6D736720
    6D6521203A29202D2D204A75657264