http://qs321.pair.com?node_id=849484

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

hello all, I am a newbie in perl. i have a text file like:
a 2 b 4,5,6 c d e 45,657,-67
i want an output like
a => [2] b =>[4,5,6] c =>[] d=> [] e=> [45,657,-67]
is it possible to make the text data into complex structure of hash array?.plz help me out asap.

20100721 Janitored by Corion: Added formatting, code tags, as per Writeup Formatting Tips

Replies are listed 'Best First'.
Re: making a text file to an hash array
by rovf (Priest) on Jul 14, 2010 at 10:47 UTC
    The main problem here seems to be the irregularity of empty hash values (i.e. d and e in your example).

    One possibility would be to split on white space, then manually loop through the array - if the array element starts with a letter, it is the hash key, and if the following array element starts with a digit, that is the value; otherwise the value would be [].

    -- 
    Ronald Fischer <ynnor@mm.st>
Re: making a text file to an hash array
by Ratazong (Monsignor) on Jul 14, 2010 at 10:51 UTC

    There are many ways to do so, and the solution (of course) depends on your requirements. Based on your example, try the following approach:

    1. read the text-file into one string
    2. split the string based on your delimiter (which seems to be a blank). This will give you an array
    3. Pass through the array.
      • check if the current element is a key (a single letter in your example, use =~ /\w/)
      • if yes: check if the next element is a value
        • if yes: store the value to the hash (using the key identified before)
        • if no: store an empty value to the hash (using the key identified before)
      • continue with the next element

    Of course you can optimize. And probably you have to adapt the algorithm - but I hope it gives you an idea!

    Rata
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: making a text file to an hash array
by jethro (Monsignor) on Jul 14, 2010 at 10:49 UTC
    my %hash; my $key; while ($_= <$file>) { my @line= split; while (@line) { my $part= shift @line; if ($part=~/^\D/) { #does not begin with a number $key= $part; $hash{$key}=[]; } else { $hash{$key}= split /,/,$part; } } }

    Untested.

    Your posting would look better if you surrounded code with <code> </code> tags by the way

    Updated, forgot a loop

Re: making a text file to an hash array
by suhailck (Friar) on Jul 14, 2010 at 11:00 UTC
    perl -MData::Dumper -e '$_=q[a 2 b 4,5,6 c d e 45,657,-67];@arr=split +/\s+/;do { $arr[$_]!~/\d+/ and splice(@arr,$_,0,[]) } for grep {($_%2 +)} 0 .. $#arr;(%hash)=@arr;print Dumper(\%hash)'

    $VAR1 = { 'e' => '45,657,-67', 'c' => [], 'a' => '2', 'b' => '4,5,6', 'd' => [] };


    UPDATE:included arrayref in splice for missing values

    ~suhail

      ... only that the OP wanted to have a reference to an empty array for missing values, not an empty string; so we would should transfer the array by map { length ? $_ : [] } @arr at the end.

      -- 
      Ronald Fischer <ynnor@mm.st>
Re: making a text file to an hash array
by johngg (Canon) on Jul 14, 2010 at 21:38 UTC

    The fact that the OP seems to want anonymous arrays for all the values makes things a bit easier. You can return an AoA of key and (possibly empty) value parts from a global match in an anonymous subroutine. Pass this into a map to deal with the value string using split.

    $ perl -MData::Dumper -E ' > $text = q{a 2 b 4,5,6 c d e 45,657,-67}; > %hash = > map { $_->[ 0 ] => [ split m{,}, $_->[ 1 ] ] } > sub { > push @arr, [ $1, $2 ] > while $_[ 0 ] =~ m{\s*([a-z])\s+([-,\d]*)}g; > return @arr; > }->( $text ); > say Data::Dumper->Dumpxs( [ \ %hash ], [ qw{ *hash } ] );' %hash = ( 'e' => [ '45', '657', '-67' ], 'c' => [], 'a' => [ '2' ], 'b' => [ '4', '5', '6' ], 'd' => [] ); $

    I hope this is helpful.

    Cheers,

    JohnGG

      Thanks so much for ur help....but suppos my text data is of hundreds of line...it is not always possible to make a hash array as u had made....them what can i do?

        You can use the same code because the \s* and \s+ in the match will also cater for newline (and carriage return if on Windows) so extracting the key and value parts will still work.

        $ perl -MData::Dumper -E ' > $text = <<EOT; > a 2 b 4,5,6 c d e 45,657,-67 > f g 23,54 h 5 i j > 286,71,90 k 7 l 72 > m 26,8 n > EOT > %hash = > map { $_->[ 0 ] => [ split m{,}, $_->[ 1 ] ] } > sub { > push @arr, [ $1, $2 ] > while $_[ 0 ] =~ m{\s*([a-z])\s+([-,\d]*)}g; > return @arr; > }->( $text ); > say Data::Dumper->Dumpxs( [ \ %hash ], [ qw{ *hash } ] );' %hash = ( 'e' => [ '45', '657', '-67' ], 'n' => [], 'a' => [ '2' ], 'm' => [ '26', '8' ], 'd' => [], 'j' => [ '286', '71', '90' ], 'l' => [ '72' ], 'c' => [], 'k' => [ '7' ], 'h' => [ '5' ], 'b' => [ '4', '5', '6' ], 'g' => [ '23', '54' ], 'f' => [], 'i' => [] ); $

        If your data is in a file then slurp the whole of the file into a scalar. Something like (using strictures and warnings):-

        my $dataFile = q{/path/to/myDataFile}; my $text = do { open my $dataFH, q{<}, $dataFile or die qq{open: < $dataFile: $!\n}; local $/; <$dataFH>; };

        I hope this answers your question.

        Cheers,

        JohnGG