Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to read a given number of lines?

0 views
Skip to first unread message

Peng Yu

unread,
Jun 8, 2010, 12:14:52 PM6/8/10
to
I want to give a given number of lines. Current, I have to write the
following code to read, for example, 3 lines. Is there a subroutine to
read a given number of lines in an array?

$line1=<IN>;
$line2=<IN>;
$line3=<IN>;

Regards,
Peng

Ralph Malph

unread,
Jun 8, 2010, 12:48:42 PM6/8/10
to
This will store the lines in the
cleverly named array @lines.
I've set $limit to 3 as in your short example
but obviously this works for any limit.
Always be sure to double check any user-inputed values!
--------------------------------
my @lines;
my $limit=3;
my $counter=0;
while($counter < $limit){
$lines[$counter] = <IN> ;
$counter++;
}

Mart van de Wege

unread,
Jun 8, 2010, 1:12:47 PM6/8/10
to
Ralph Malph <ra...@happydays.com> writes:

or:

my @lines;
my $limit = 3;
for my $line(1..$limit) {
$lines[$line] = <IN>
}

But then again I have a personal dislike of counters and flags, so I
tend to look for ways to avoid using them.

--
"We will need a longer wall when the revolution comes."
--- AJS, quoting an uncertain source.

Mart van de Wege

unread,
Jun 8, 2010, 1:14:43 PM6/8/10
to

And that was an off-by-one error. Saw it as I hit 'post'.

So the correct code would of course be:

my @lines;
my $limit = 3;

for my $line(0..$limit-1) {
$lines[$line] = <IN>

Ralph Malph

unread,
Jun 8, 2010, 1:21:01 PM6/8/10
to
In some senses you original code was correct although
it didn't fill $lines[0].
As required, it read a certain number of lines into an array.
Nonetheless, I suggest you start disliking silly errors
more than you dislike counters and flags.
HTH

Ben Morrow

unread,
Jun 8, 2010, 1:31:11 PM6/8/10
to

Quoth Mart van de Wege <mvd...@mail.com>:

> >
> > my @lines;
> > my $limit = 3;
> > for my $line(1..$limit) {
> > $lines[$line] = <IN>
> > }
> >
> > But then again I have a personal dislike of counters and flags, so I
> > tend to look for ways to avoid using them.
>
> And that was an off-by-one error. Saw it as I hit 'post'.
>
> So the correct code would of course be:
>
> my @lines;
> my $limit = 3;
> for my $line(0..$limit-1) {
> $lines[$line] = <IN>
> }

Better would be

my @lines;
push @lines, <IN> for 1..3;

though I would probably rather have

my @lines = map <IN>, 1..3;

since I don't like variable declarations just hanging around not doing
anything useful.

Ben

Willem

unread,
Jun 8, 2010, 1:42:29 PM6/8/10
to
Ben Morrow wrote:
) Better would be
)
) my @lines;
) push @lines, <IN> for 1..3;
)
) though I would probably rather have
)
) my @lines = map <IN>, 1..3;
)
) since I don't like variable declarations just hanging around not doing
) anything useful.

BZZT!

Both of your examples will read the entire file into @lines.
Left as an exercise to figure out why this is and how to fix it.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT

Ralph Malph

unread,
Jun 8, 2010, 1:56:45 PM6/8/10
to
On 6/8/2010 1:42 PM, Willem wrote:
> Ben Morrow wrote:
> ) Better would be
> )
> ) my @lines;
> ) push @lines,<IN> for 1..3;
> )
> ) though I would probably rather have
> )
> ) my @lines = map<IN>, 1..3;
> )
> ) since I don't like variable declarations just hanging around not doing
> ) anything useful.
>
> BZZT!
>
> Both of your examples will read the entire file into @lines.
> Left as an exercise to figure out why this is and how to fix it.
Q: "How to fix it".
A: They need to stop trying to be so fucking clever. Clever kills.


Ben Morrow

unread,
Jun 8, 2010, 2:51:37 PM6/8/10
to

Quoth Ralph Malph <ra...@happydays.com>:

> On 6/8/2010 1:42 PM, Willem wrote:
> > Ben Morrow wrote:
> > ) Better would be
> > )
> > ) my @lines;
> > ) push @lines,<IN> for 1..3;
> > )
> > ) though I would probably rather have
> > )
> > ) my @lines = map<IN>, 1..3;
> > )
> > ) since I don't like variable declarations just hanging around not doing
> > ) anything useful.
> >
> > BZZT!
> >
> > Both of your examples will read the entire file into @lines.
> > Left as an exercise to figure out why this is and how to fix it.

True. Good catch. (Or possibly stupid mistake on my part.)

> Q: "How to fix it".
> A: They need to stop trying to be so fucking clever. Clever kills.

'They' in this case being me? I wasn't trying to be clever, I was trying
to write the code in a simple and obvious way. Counting indices by hand
is much easier to get wrong than letting perl count them for you.

Ben

Willem

unread,
Jun 8, 2010, 4:14:09 PM6/8/10
to
Ben Morrow wrote:
) 'They' in this case being me? I wasn't trying to be clever, I was trying
) to write the code in a simple and obvious way. Counting indices by hand
) is much easier to get wrong than letting perl count them for you.

You mean like: for (0..2) { $lines[$_] = <IN> }

But in any case, this mistake is not a cleverness one,
because the exact same problem exists in the code:

for (my $i = 0; $i < 3; $i++) {
push @lines, <IN>;
}

Which I would hardly call 'clever'.

Marc Girod

unread,
Jun 8, 2010, 4:58:14 PM6/8/10
to
On Jun 8, 9:14 pm, Willem <wil...@turtle.stack.nl> wrote:

> You mean like: for (0..2) { $lines[$_] = <IN> }

I'am not smart enough to not try being clever.
Besides (and for wrong reasons: I used to like Lisp), I like maps.
So, I was thinking of the following minimal(?) fix(?):

my @lines = map scalar <IN>, 1..3;

Marc

Ben Morrow

unread,
Jun 8, 2010, 5:46:06 PM6/8/10
to

Quoth Willem <wil...@turtle.stack.nl>:

> Ben Morrow wrote:
> ) 'They' in this case being me? I wasn't trying to be clever, I was trying
> ) to write the code in a simple and obvious way. Counting indices by hand
> ) is much easier to get wrong than letting perl count them for you.
>
> You mean like: for (0..2) { $lines[$_] = <IN> }

Mmm, I suppose. I think my problem with that is that I just dislike
array indices other than [0] and [-1]: I think of arrays as 'frozen
lists', so either you iterate over the whole thing or you attack it from
the ends.

The original buggy code was essentially

for (1..3) { $lines[$_] = <IN> }

and the use of explicit subscripts disguises the fact that there's an
extra 'undef' element on the beginning.

> But in any case, this mistake is not a cleverness one,
> because the exact same problem exists in the code:
>
> for (my $i = 0; $i < 3; $i++) {
> push @lines, <IN>;
> }
>
> Which I would hardly call 'clever'.

I suspect that anyone approaching that code who didn't have a background
in C *would* call it clever, or at any rate much more complicated and
less comprehensible than a simple

for (1..3)

Something like

repeat (3) {...}

would be even simpler, of course, but unfortunately Perl doesn't allow
modules to create new syntax like that[0].

Ben

[0] ...without support code that will make you go blind.
c.f. Devel::Declare, and/or source filters.

Uri Guttman

unread,
Jun 8, 2010, 9:29:54 PM6/8/10
to
>>>>> "BM" == Ben Morrow <b...@morrow.me.uk> writes:

BM> Quoth Willem <wil...@turtle.stack.nl>:


>> Ben Morrow wrote:
>> ) 'They' in this case being me? I wasn't trying to be clever, I was trying
>> ) to write the code in a simple and obvious way. Counting indices by hand
>> ) is much easier to get wrong than letting perl count them for you.
>>
>> You mean like: for (0..2) { $lines[$_] = <IN> }

BM> Mmm, I suppose. I think my problem with that is that I just dislike
BM> array indices other than [0] and [-1]: I think of arrays as 'frozen
BM> lists', so either you iterate over the whole thing or you attack it from
BM> the ends.

amusing viewpoint but what about random accesses, direct accesses (it
happens), splicing (both inserts and deletes), etc. true, i do what you
say most of the time but i still keep those other things in my
toolbox. :)

uri

--
Uri Guttman ------ u...@stemsystems.com -------- http://www.sysarch.com --
----- Perl Code Review , Architecture, Development, Training, Support ------
--------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------

Mart van de Wege

unread,
Jun 9, 2010, 1:28:55 AM6/9/10
to
Ralph Malph <ra...@happydays.com> writes:

>>> my @lines;
>>> my $limit = 3;
>>> for my $line(1..$limit) {
>>> $lines[$line] =<IN>
>>> }
>>>
>>> But then again I have a personal dislike of counters and flags, so I
>>> tend to look for ways to avoid using them.
>>
>> And that was an off-by-one error. Saw it as I hit 'post'.
>>
>> So the correct code would of course be:
>>
>> my @lines;
>> my $limit = 3;
>> for my $line(0..$limit-1) {
>> $lines[$line] =<IN>
>> }
> In some senses you original code was correct although
> it didn't fill $lines[0].
> As required, it read a certain number of lines into an array.
> Nonetheless, I suggest you start disliking silly errors
> more than you dislike counters and flags.
> HTH

You know, if you want your advice to be taken seriously, it would be
better not to behave like a complete twit.

Mart

bankair

unread,
Jun 9, 2010, 4:12:44 AM6/9/10
to

Hi,

May be the special var "$." (line NBR of the last read file handle)
could help :
my @lines;
while (<>) { push @lines,$_ if($.<4) }

Regards,
Alexandre

Uri Guttman

unread,
Jun 9, 2010, 4:17:33 AM6/9/10
to
>>>>> "b" == bankair <ban...@gmail.com> writes:

b> On Jun 8, 6:14 pm, Peng Yu <pengyu...@gmail.com> wrote:
>> I want to give a given number of lines. Current, I have to write the
>> following code to read, for example, 3 lines. Is there a subroutine to
>> read a given number of lines in an array?
>>
>> $line1=<IN>;
>> $line2=<IN>;
>> $line3=<IN>;

b> Hi,

b> May be the special var "$." (line NBR of the last read file handle)
b> could help :
b> my @lines;
b> while (<>) { push @lines,$_ if($.<4) }

and what happens to the lines after the third one? that will read to eof
which is likely not wanted.

better to invert the loop:

while ( $. < 4 ) {
push @lines, scalar <> ;
}

or for those lovers of one liners:

push @lines, scalar <> while $. < 4 ;

bankair

unread,
Jun 9, 2010, 4:41:18 AM6/9/10
to
On Jun 9, 10:17 am, "Uri Guttman" <u...@StemSystems.com> wrote:

> >>>>> "b" == bankair  <bank...@gmail.com> writes:
>
>   b> On Jun 8, 6:14 pm, Peng Yu <pengyu...@gmail.com> wrote:
>   >> I want to give a given number of lines. Current, I have to write the
>   >> following code to read, for example, 3 lines. Is there a subroutine to
>   >> read a given number of lines in an array?
>   >>
>   >> $line1=<IN>;
>   >> $line2=<IN>;
>   >> $line3=<IN>;
>
>   b> Hi,
>
>   b> May be the special var "$." (line NBR of the last read file handle)
>   b> could help :
>   b> my @lines;
>   b> while (<>) { push @lines,$_ if($.<4) }
>
> and what happens to the lines after the third one? that will read to eof
> which is likely not wanted.
>
> better to invert the loop:
>
> while ( $. < 4 ) {
>         push @lines, scalar <> ;
>
> }
>
> or for those lovers of one liners:
>
>         push @lines, scalar <> while $. < 4 ;

Ah ! Your "scalar <>" (thank you) gave me another idea :

my @lines = grep {defined $_} map {scalar <>} (1..3);

Martijn Lievaart

unread,
Jun 9, 2010, 5:06:01 AM6/9/10
to
On Wed, 09 Jun 2010 04:17:33 -0400, Uri Guttman wrote:

>>>>>> "b" == bankair <ban...@gmail.com> writes:
>
> b> On Jun 8, 6:14 pm, Peng Yu <pengyu...@gmail.com> wrote:
> >> I want to give a given number of lines. Current, I have to write
> >> the following code to read, for example, 3 lines. Is there a
> >> subroutine to read a given number of lines in an array?
> >>
> >> $line1=<IN>;
> >> $line2=<IN>;
> >> $line3=<IN>;
>
> b> Hi,
>
> b> May be the special var "$." (line NBR of the last read file handle)
> b> could help :
> b> my @lines;
> b> while (<>) { push @lines,$_ if($.<4) }
>
> and what happens to the lines after the third one? that will read to eof
> which is likely not wanted.
>
> better to invert the loop:
>
> while ( $. < 4 ) {
> push @lines, scalar <> ;
> }
>
> or for those lovers of one liners:
>
> push @lines, scalar <> while $. < 4 ;

Those have the potential of an infinite loop when the file has less than
3 lines. Besides, even when fixed, the 'push @lines, scalar <>' pushes
undef at eof, so I very much doubt this is what you want.

So I guess the best option (assuming you want to exit early at eof, not
push undefs):


while (<>) {
last if ($.>=4)
push @lines,$_;
}

Eventually followed by

push @lines, undef for ($. .. 3);

If you do want undefs for missing lines.

M4

Justin C

unread,
Jun 9, 2010, 7:23:39 AM6/9/10
to


The variable $. holds the current line number for the last filehandle
accessed. It may be useful to you, see perldoc perlvar for details.

Justin.

--
Justin C, by the sea.

Peng Yu

unread,
Jun 9, 2010, 11:48:43 AM6/9/10
to

I don't understand why 'scalar' has to be used. Would you please let
me know where I should read in man page to understand file handle in
scalar and list context.

Marc Girod

unread,
Jun 9, 2010, 1:17:24 PM6/9/10
to
On Jun 9, 4:48 pm, Peng Yu <pengyu...@gmail.com> wrote:

> I don't understand why 'scalar' has to be used. Would you please let
> me know where I should read in man page to understand file handle in
> scalar and list context.

I/O Operators in perlop?
In scalar context, evaluating a filehandle in angle brackets
yields the
next line from that file (the newline, if any, included), or
"undef" at
end-of-file or on error.
...
If a <FILEHANDLE> is used in a context that is looking for a
list, a list
comprising all input lines is returned, one line per list
element.

and then, of course, scalar in perlfunc...
scalar EXPR
Forces EXPR to be interpreted in scalar context and
returns the
value of EXPR.

Marc

Mart van de Wege

unread,
Jun 10, 2010, 4:53:00 PM6/10/10
to
Peng Yu <peng...@gmail.com> writes:

As Marc pointed out, using the readline operator <> in scalar context
reads only one line.

Why it is necessary here is because the above statement would normally
evaluate <> in list context. I'm a bit unclear if that is because of the
array assignment or the map function. I believe it is the map function
forcing a list context here, but I could be wrong. Even if I am,
assigning to an array definitely forces list context.

Ben Morrow

unread,
Jun 10, 2010, 5:11:10 PM6/10/10
to

Quoth Mart van de Wege <mvd...@mail.com>:
> Why it is necessary here is because the above statement would normally
> evaluate <> in list context. I'm a bit unclear if that is because of the
> array assignment or the map function. I believe it is the map function
> forcing a list context here, but I could be wrong. Even if I am,
> assigning to an array definitely forces list context.

map always evaluates its first argument (EXPR or BLOCK) in list context.
This makes it possible to change the length of the returned list.

Ben

Dr.Ruud

unread,
Jun 11, 2010, 7:15:40 PM6/11/10
to
Peng Yu wrote:

$ echo -e 'a\nb\nc\nd\ne\n' | perl -wle'

sub get_lines {
my ( $fh, $max, $aref )= @_;
my $count;
while ( ++$count <= $max and defined( my $line= <$fh> ) ) {
push @$aref, $line;
}
return $count;
}

my @lines;
get_lines +STDIN, 2, \@lines;
print for @lines;
'
a

b

--
Ruud

0 new messages