Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Adding text file data to hashes and array

by Tigor (Novice)
on Feb 13, 2019 at 10:38 UTC ( #1229866=perlquestion: print w/replies, xml ) Need Help??
Tigor has asked for the wisdom of the Perl Monks concerning the following question:

I have a text file which contains fruits data which get sold every month as below

file name is fruits.txt

the text file data looks like as below.Please  get average of the values stored in array as well.I have tried harder to get the ouput but stuck.
Fruit Jan feb mar apr Apple 40 45 50 54 orange 12 25 24 29 Pineapple 10 20 30 40

I want output as below

{apple => [40,45,50,54] Orange =>[12,25,24,29]}

i have written a code for the above desired ouput.Please find my code below

use strict; use warnings; my $filename = 'fruits.txt'; #opening the text file open(DATA, '<', $filename) or die "Could not open file '$filename' $!"; readline(DATA);#skipping the header my %data; while (<DATA>) { my @fields = split; my $key = join(' ', splice(@fields, 0, 2)); $data{$key} = \@fields; } for my $key (sort(keys(%data))) { printf("%s=> %s\n", $key, join(' ', @{$data{$key}})); }

Replies are listed 'Best First'.
Re: Adding text file data to hashes and array
by roboticus (Chancellor) on Feb 13, 2019 at 16:10 UTC

    Tigor:

    You were pretty close with your code. The problem is how you built your key.

    In your desired output, you show that you want to use the first column as the key, but you used:

    my $key = join(' ', splice(@fields, 0, 2)); \_______ ____________/ \ v \ (1) \___ __________________________/ v (2)

    That explicitly (1) takes the first two columns out of @fields (two columns starting at zero), and then (2) joins them together with a space to build $key.

    Since you wanted only the first column as the key, you could have used:

    my $key = splice(@fields, 0, 1);

    which would have taken just the first column and used it as the key. However, there are other ways. The shift operator, for example, will remove the first item from a list, so you could get the same result like this:

    my $key = shift @fields;

    However the method I would use is the same one proposed by poj, which is to do it when you split the line into fields:

    my ($key, @fields) = split;

    Here, when split creates a list of values, it puts the first one in $key and the rest of them in @fields. Note: when you do it like this, the first array on the left side will consume *all* the values. So doing something like the following:

    my ($key,@first_quarter, $apr) = split;

    leaves the last value undefined. You'd get $key='Apple', @fields=[40, 45, 50, 54], and $apr=undef for the first line of data.

    Update: I bumbled Tigor's name. Thanks, chirooba! ;^)

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: Adding text file data to hashes and array
by poj (Abbot) on Feb 13, 2019 at 11:29 UTC

    Looks like the key is column 1 only.

    while (<DATA>) { my ($key,@fields) = split; $data{$key} = \@fields; }
    poj
Re: Adding text file data to hashes and array
by thanos1983 (Parson) on Feb 13, 2019 at 15:38 UTC

    Hello Tigor,

    I was under the impression that you want also to calculate the average or the values e.g. (see bellow):

    #!/usr/bin/perl use strict; use warnings; use IO::All; use Data::Dumper; use List::Util qw(sum); sub mean { return sum(@_)/@_; } my @lines = io('in.txt')->chomp->slurp; splice @lines, 0, 1; # remove first line my %hash; foreach my $line (@lines) { $line =~ s/^\s+//; my @elements = split /\s+/, $line; my $reference = splice @elements, 0, 1; $hash{$reference} = mean(@elements); } print Dumper \%hash; __END__ $ perl test.pl $VAR1 = { 'Pineapple' => '25', 'Apple' => '47.25', 'orange' => '22.5' };

    If not you can simply do this (see bellow):

    #!/usr/bin/perl use strict; use warnings; use IO::All; use Data::Dumper; my @lines = io('in.txt')->chomp->slurp; splice @lines, 0, 1; # remove first line my %hash; foreach my $line (@lines) { $line =~ s/^\s+//; my @elements = split /\s+/, $line; $hash{splice @elements, 0, 1} = \@elements; } print Dumper \%hash; __END__ $ perl test.pl $VAR1 = { 'Pineapple' => [ '10', '20', '30', '40' ], 'orange' => [ '12', '25', '24', '29' ], 'Apple' => [ '40', '45', '50', '54' ] };

    I hope this helps, BR.

    Seeking for Perl wisdom...on the process of learning...not there...yet!

      Two nits: Why use splice @lines, 0, 1; instead of shift, and why use split /\s+/ when split ' ' does the same thing but discards leading whitespace? splice @elements, 0, 1; discards the first element regardless of what it contains, even if the file format changes and there is no more whitespace at the front of the lines.

        Hello haukex,

        Yes you are right, I was not thinking clearly on that day and I made the code more complex without any reason :).

        Thanks for pointing out minor possible improvements.

        BR / Thanos

        Seeking for Perl wisdom...on the process of learning...not there...yet!

      Hi thanos1983,The code which was shared by you absolutely brilliant piece of code and helped me a lot but what if there is a bit change in the text file mentioned below input file.I have tried but i am getting the output as {''=>[],Apple =>[A,40,45,50,54]} with first line empty and actual data is starting after the comma seperation & A in displaying in an array actually it has to dispay as {Apple-A =>[40,45,50,54]} .Any help is appreciated

      Below is the code used to achieve the output

      use strict; use warnings; use IO::All; use Data::Dumper; my @elements =(); my @lines = io('test_scores.txt')->chomp->slurp; splice @lines, 0, 1; # remove first line my %hash; foreach my $line (@lines) { $line =~ s/^\s+//; my @elements = split /\s+/, $line; $hash{splice @elements, 0, 1} = \@elements; } print Dumper \%hash;

      below is the Input file

      fruit Jan feb mar apr Apple A 40 45 50 54 orange O 12 25 24 29 Pineapple P 10 20 30 40

      output should be as below

      {Apple-A =>[40,45,50,54]}

        Make the key by joining the first 2 fields. see splice and join

        foreach my $line (@lines) { $line =~ s/^\s+//; my @elements = split /\s+/, $line; my $key = join '-',splice @elements, 0, 2; # 2 col key $hash{$key} = \@elements if length($key) > 0; # no blank keys }
        poj

        The code you posted in the root node works for this case...

Re: Adding text file data to hashes and array
by roboticus (Chancellor) on Feb 13, 2019 at 16:09 UTC

    duplicate node, please delete

    PublicAccess:

    You were pretty close with your code. The problem is how you built your key.

    In your desired output, you show that you want to use the first column as the key, but you used:

    my $key = join(' ', splice(@fields, 0, 2)); \_______ ____________/ \ v \ (1) \___ __________________________/ v (2)

    That explicitly (1) takes the first two columns out of @fields (two columns starting at zero), and then (2) joins them together with a space to build $key.

    Since you wanted only the first column as the key, you could have used:

    my $key = splice(@fields, 0, 1);

    which would have taken just the first column and used it as the key. However, there are other ways. The shift operator, for example, will remove the first item from a list, so you could get the same result like this:

    my $key = shift @fields;

    However the method I would use is simply to do it when you split the line into fields:

    my ($key, @fields) = split;

    Here, when split creates a list of values, it puts the first one in $key and the rest of them in @fields. Note: when you do it like this, the first array on the left side will consume *all* the values. So doing something like the following:

    my ($key,@first_quarter, $apr) = split;

    leaves the last value undefined. You'd get $key='Apple', @fields=[40, 45, 50, 54], and $apr=undef for the first line of data.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1229866]
Approved by Corion
Front-paged by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (7)
As of 2019-03-19 14:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    How do you Carpe diem?





    Results (91 votes). Check out past polls.

    Notices?
    • (Sep 10, 2018 at 22:53 UTC) Welcome new users!