http://www.perlmonks.org?node_id=1070088

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

Hi, I have a file with these values,
Name a b c d e f g h
How can i save the first 3 values i.e. (a,b,c) to 3 different variables? i.e.
$i = a $j = b $k = c
Need to repeat till the end of the file, so the next iteration these variable should have values,
$i = d $j = e $ = f

Replies are listed 'Best First'.
Re: Save first n values from a file
by LanX (Saint) on Jan 10, 2014 at 10:40 UTC
    file handles return single lines in scalar context

    while ( my $a =<DATA> ){ my $b=<DATA>; my $c=<DATA>; print $a; } # while ( my $a =<DATA>, my $b=<DATA>, my $c=<DATA> ){ # print $a; # } __DATA__ a b c d e f g h

    please note the difference, the second version will stop after printing "d", since the last group has only 2 entries (i.e. $c is undef)

    Cheers Rolf

    ( addicted to the Perl Programming Language)

Re: Save first n values from a file
by Random_Walk (Prior) on Jan 10, 2014 at 10:33 UTC

    Perhaps a hash, or an array is would suit your purpose better. Here is an example using an array, also showing a way to put the vals in $i, $j, $k and a way to use a hash.

    Update: Added hash demo to code too, and better behaviour when it runs out of values

    use strict; use warnings; my @names; while (my $name = <DATA>) { chomp $name; # remove newline push @names, $name; } print "The third name is $names[2]\n"; my @copy = @names; # take a copy for the hash demo my ($i, $j, $k); while (@names) { for (\$i, \$j, \$k) { if (@names) { $$_ = shift @names; } else { $$_ = 'ran out of records'; # could use undef too } } print "i: $i j:$j k: $k \n"; } # and with a hash my %hash; while (@copy) { %hash = (i=>'', j=>'', k=>''); # clear the hash for my $key (qw(i j k)) { $hash{$key} = shift @copy if @copy; } print "the hash contains $hash{$_} under $_\n" for ('i'..'k'); } __DATA__ a b c d e f g h

    Cheers,
    R.

    Pereant, qui ante nos nostra dixerunt!
Re: Save first n values from a file
by johngg (Canon) on Jan 10, 2014 at 12:09 UTC

    This code builds an AoA by processing three lines at a time and pushing an anonymous array of chomped lines for each group.

    $ perl -Mstrict -Mwarnings -MData::Dumper -e ' sub groupsOf (&$@); open my $inFH, q{<}, \ <<EOD or die $!; a b c d e f g h EOD my @arr; push @arr, groupsOf { chomp @_; [ @_ ] } 3, <$inFH>; sub groupsOf (&$@) { my $rcToRun = shift; my $groupsOf = shift; my $rcDoIt; $rcDoIt = sub { $rcToRun->( map shift, 1 .. ( @_ < $groupsOf ? @_ : $groupsOf ) ), @_ ? &$rcDoIt : (); }; &$rcDoIt; } print Data::Dumper->Dumpxs( [ \ @arr ], [ qw{ *arr } ] );' @arr = ( [ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ], [ 'g', 'h' ] ); $

    I hope this is of interest.

    Update: Simpler and assigns to three variables rather than constructing an AoA.

    $ perl -Mstrict -Mwarnings -E ' > open my $inFH, q{<}, \ <<EOD or die $!; > a > b > c > d > e > f > g > h > EOD > > while ( not eof $inFH ) > { > my( $i, $j, $k ) = > map { chomp; $_ } > map { eof $inFH ? () : scalar <$inFH> } > 1 .. 3; > say > q{$i - }, defined $i ? qq{$i; } : q{undef; }, > q{$j - }, defined $j ? qq{$j; } : q{undef; }, > q{$k - }, defined $k ? $k : q{undef}; > }' $i - a; $j - b; $k - c $i - d; $j - e; $k - f $i - g; $j - h; $k - undef $

    Cheers,

    JohnGG

Re: Save first n values from a file
by Lennotoecom (Pilgrim) on Jan 10, 2014 at 12:16 UTC
    this is the dark arts ^ ^,
    but seriously, I think other monks won't approve, still:
    for $x (f .. j){ chomp(${$x} = <DATA>); } print "$f $g $h $i $j\n"; __DATA__ a b c d e
    update*
    addressing the authors exact demands
    here an addition:
    do{for $x (i, g, k){ chomp(${$x} = <DATA>); } print "$i $g $k\n";} until eof; __DATA__ a b c d e f g h
    output:
    a b c d e f g h
      > I think other monks won't approve, still:

      Don't you think, you should at least mention no strict 'refs' ? :)

      Cheers Rolf

      ( addicted to the Perl Programming Language)

        yes, sorry
        just couldn't restrain myself :)
        I hope the readers will understand
Re: Save first n values from a file
by kcott (Archbishop) on Jan 12, 2014 at 14:53 UTC

    Here's another way to do it:

    #!/usr/bin/env perl -l use strict; use warnings; my @values; while (<DATA>) { chomp; push @values, $_; if (@values == 3) { process_values(@values); @values = (); } } process_values(@values) if @values; sub process_values { my ($i, $j, $k) = @_; print '$i = ', defined $i ? $i : '<undefined>'; print '$j = ', defined $j ? $j : '<undefined>'; print '$k = ', defined $k ? $k : '<undefined>'; } __DATA__ a b c d e f g h

    Output:

    $i = a $j = b $k = c $i = d $j = e $k = f $i = g $j = h $k = <undefined>

    -- Ken

Re: Save first n values from a file
by robby_dobby (Hermit) on Jan 13, 2014 at 05:57 UTC
    Others have offered varied solutions. Alternatively, you can use splice. Once you have read all the names into an array, you can loop through that array to gather items 3 at a time:
    while(@names) { my ($i, $j, $k) = splice (@names, 0, 3); printf('$i is %s, $j is %s, $k is %s', $i, $j, $k); print "\n"; }
    Note that if you have strict or warnings enabled, you will get errors like: "Use of uninitialized value $k in printf". You can add error/null checking here to handle all of these. This would also mutate the @names array - keep a defensive copy around. :-)
Re: Save first n values from a file
by Anonymous Monk on Jan 10, 2014 at 20:57 UTC
    Fastest way by far:
    • seek() to a position, relative to end-of-file, that you are quite sure is long enough to fit. ...
    • Read a string starting from that position.
    • Use a regex anchored at end-of-string to carve off the last three digits, e.g. /(\d+)\n(\d+)\n(\d+)$/ this assuming there are no whitespaces.
    • The numbers you want are $1, $2, $3. (If they aren't, then die() because your assumption about "what you are quite sure is long enough" wasn't.)
    You don't need to slog through an arbitrarily-long random access file just to find out what's at the end of it.
Re: Save first n values from a file
by pvaldes (Chaplain) on Jan 12, 2014 at 15:19 UTC
    use strict; use warnings; my @foo = (); while (<DATA>){ chomp; if ($. < 4){push @foo, $_}} print "my first variable is $foo[0]"; print "my second variable is $foo[1]"; print "my third variable is $foo[2]"; __DATA__ one two a beautiful tree, maybe an oak?

    no need to read after "n lines"

    And you can add also a fifth line to rename your variables and that's all:

     my ($ball,$dog,$bird) = ($fo[1],$fo[2],$fo[0]);
Re: Save first n values from a file
by Anonymous Monk on Jan 10, 2014 at 20:58 UTC
    Correction: "read a chunk of data regardless of 'string' boundaries." The actual bytes, please.