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

Question in Perl Arrays

1 view
Skip to first unread message

Yogi

unread,
Jul 17, 2008, 3:52:08 AM7/17/08
to
Hi,

I am trying to understand how arrays work in scalar context. Here is
the question:

@a = (10,20,30,40,50);
@b = @a[0..3];
print "[@b] \n";

when I run this script, I am getting proper result i.e. o/p is: [10 20
30 40]
But when I do this change:
@a = (10,20,30,40,50);
@b = $a[0..3]; # THIS LINE IS CHANGED
print "[@b] \n";

I get o/p as: [20]. why? why first element of the range operator is
ignored and 2nd element is assigned to @b. I am trying this just to
satisfy my curiosity.

Regards,

Gunnar Hjalmarsson

unread,
Jul 17, 2008, 5:04:50 AM7/17/08
to
Yogi wrote:
> I am trying to understand how arrays work in scalar context.

Your example below has nothing to do with scalar context.

Missing:

use strict;
use warnings;

> @a = (10,20,30,40,50);
> @b = @a[0..3];
> print "[@b] \n";
>
> when I run this script, I am getting proper result i.e. o/p is: [10 20
> 30 40]
> But when I do this change:
> @a = (10,20,30,40,50);
> @b = $a[0..3]; # THIS LINE IS CHANGED
> print "[@b] \n";
>
> I get o/p as: [20]. why?

Probably because $a[0..3] is plain wrong. An array slice never starts
with '$'.

If warnings had been enabled, Perl would have objected.

--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl

Yogi

unread,
Jul 17, 2008, 5:15:43 AM7/17/08
to

Hi,
This is giving me same output (with warning ofcourse):
use strict;
use warnings;
my @b=();

my @a = (10,20,30,40,50);
@b = $a[0..3];
print "[@b] \n";

If Array slice must not start with '$', it should not give me 20 as o/
p.
Please suggest.
-Regards

RedGrittyBrick

unread,
Jul 17, 2008, 5:42:20 AM7/17/08
to

Yes it should.

C:\>perl -e "print 0..3"
0123
C:\>perl -e "print scalar (0..3)"
1

So 0..3 evaluates to 1 in a scalar context.
Therefore $a[0..3] is $a[1]
Presumably because array indexing uses a scalar index.


--
RGB

Mirco Wahab

unread,
Jul 17, 2008, 5:46:03 AM7/17/08
to
RedGrittyBrick wrote:
>> my @a = (10,20,30,40,50);
>> @b = $a[0..3];
>> print "[@b] \n";
>>
>> If Array slice must not start with '$', it should not give me 20 as o/
>> p.
>
> Yes it should.
>
> C:\>perl -e "print 0..3"
> 0123
> C:\>perl -e "print scalar (0..3)"
> 1
>
> So 0..3 evaluates to 1 in a scalar context.
> Therefore $a[0..3] is $a[1]
> Presumably because array indexing uses a scalar index.

Wrong. This is the flip-flop operator.
In scalar context with two constants,
it's matched against $.

...
$.= 2;
print "$.\n";
print $a[0..3], "\n"; # will return $. if first operand (0) is false
...


Regards

M.

Yogi

unread,
Jul 17, 2008, 7:25:04 AM7/17/08
to

Is there any simple document which explains how its working? I tried
reading thru perldoc for .. operator, but am really confused between
list and scalar contexts?

Regards,

Leon Timmermans

unread,
Jul 17, 2008, 7:49:34 AM7/17/08
to

The .. operator can be quite confusing when it comes to context. You
should read the perlop on "Range operators" for a detailed information
about it. As for contexts: @a[] evaluates its index under list context, $a
[] does so under scalar context. In both cases, that makes a lot of sense
when you realize what they do.

Leon Timmermans

Yogi

unread,
Jul 17, 2008, 8:11:02 AM7/17/08
to

Thanks all. I started picking up bit of this context usage. :)
-Regards

RedGrittyBrick

unread,
Jul 17, 2008, 8:39:57 AM7/17/08
to

TFTC

--
RGB

Mirco Wahab

unread,
Jul 17, 2008, 8:42:46 AM7/17/08
to
RedGrittyBrick wrote:
> Mirco Wahab wrote:
>> RedGrittyBrick wrote:
>>> So 0..3 evaluates to 1 in a scalar context.
>>> Therefore $a[0..3] is $a[1]
>>> Presumably because array indexing uses a scalar index.
>
> TFTC

Oops, what's the meaning of that?


Consider:

...

my @arr = 0..999; # some data
$. = $[; # $. to first array index

for (@arr) {
print "$_\n" if 100..120;
++$.
}

...

Regards

M.

RedGrittyBrick

unread,
Jul 17, 2008, 9:08:15 AM7/17/08
to
Mirco Wahab wrote:
> RedGrittyBrick wrote:
>>
>> TFTC
>
> Oops, what's the meaning of that?

It is an abbreviation of "Thanks For The Correction".

Sometimes I accidentally use abbreviations which are common in another
forum but rare in this one.

SFCC

--
RGB

xho...@gmail.com

unread,
Jul 17, 2008, 11:04:54 AM7/17/08
to
Yogi <yogeshk...@gmail.com> wrote:
> On Jul 17, 2:46=A0pm, Mirco Wahab <wa...@chemie.uni-halle.de> wrote:
...

> >
> > Wrong. This is the flip-flop operator.
> > In scalar context with two constants,
> > it's matched against $.
> >
....

>
> Is there any simple document which explains how its working?

Probably not. It is complex, so a simple document would be misleading.

> I tried
> reading thru perldoc for .. operator, but am really confused between
> list and scalar contexts?

Can you clarify the nature of your confusion? Are you confused about how
.. behaves in each context, or how to determine which context it is in?

On the first point, I'm somewhat confused myself. I've never fully
understand what the flip-flop mode does, but I understand enough to avoid
accidentally using it, so my confusion is safely sequestered.

On the second point, that is not an issue specific to "..", but a general
Perl issue. In this case, it is intuitive to me that the subscript of
$x[] is in scalar and @x[] is in list, but if you want to discover that
by experimentation, you can make a tattler function:
sub tattle { warn "wantarray: ", wantarray };

And then replace the ".." construct with an invocation of tattle to see
what context your are in.


Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.

Sherman Pendley

unread,
Jul 17, 2008, 11:31:28 AM7/17/08
to
RedGrittyBrick <RedGrit...@SpamWeary.foo> writes:

> C:\>perl -e "print scalar (0..3)"
> 1
>
> So 0..3 evaluates to 1 in a scalar context.

Huh? This is the first time in quite a while that Perl has managed to
surprise me. I would have expected the above to print 4 - the number
of elements in the list.

Why 1?

sherm--

--
My blog: http://shermspace.blogspot.com
Cocoa programming in Perl: http://camelbones.sourceforge.net

Sherman Pendley

unread,
Jul 17, 2008, 11:33:40 AM7/17/08
to
Mirco Wahab <wa...@chemie.uni-halle.de> writes:

>> So 0..3 evaluates to 1 in a scalar context.
>> Therefore $a[0..3] is $a[1]
>> Presumably because array indexing uses a scalar index.
>
> Wrong. This is the flip-flop operator.
> In scalar context with two constants,
> it's matched against $.

D'oh! Never mind my question then. I should have read the whole thread
before responding.

It's rather embarrassing that I forgot about the range operator, after
having talked about it just a few days ago... That'll teach me to post
before I'm done with my first coffee of the day. :-(

Leon Timmermans

unread,
Jul 17, 2008, 11:57:54 AM7/17/08
to
On Thu, 17 Jul 2008 11:31:28 -0400, Sherman Pendley wrote:

> RedGrittyBrick <RedGrit...@SpamWeary.foo> writes:
>
>> C:\>perl -e "print scalar (0..3)"
>> 1
>>
>> So 0..3 evaluates to 1 in a scalar context.
>
> Huh? This is the first time in quite a while that Perl has managed to
> surprise me. I would have expected the above to print 4 - the number of
> elements in the list.
>
> Why 1?
>
> sherm--

Because in scalar context it doesn't produce a range, but a flip-flop. It
returns 1 if the current line number (in the variable $.) is equal to the
first number and continues to do so until the line number is equal to the
second number. This is a heritage from sed and awk.

Since he doesn't do any reading, $. == 0, so it returns 1.

Returning its length is a property of arrays, *not a general feature of
list* or functions or builtins returning lists. m//, s///, qw//, qx//,
reverse, split, splice, split, sort, times, unpack, readdir, stat,
caller, get*/set*, localtime, gmtime and possibly a few more don't do so
either. In fact, I think grep and map are the only builtins that mimic
the behavior of arrays.

Leon Timmermans

Ben Morrow

unread,
Jul 17, 2008, 12:58:06 PM7/17/08
to

Quoth xho...@gmail.com:

>
> On the first point, I'm somewhat confused myself. I've never fully
> understand what the flip-flop mode does, but I understand enough to avoid
> accidentally using it, so my confusion is safely sequestered.

It's designed for use with -n. Something like

perl -ne'/foo/../bar/ and print'

will print all the lines from 'foo' to 'bar', and

perl -ne'3../STOP/ and print'

will print from the third line up to one containing 'STOP'. It is the
same as the ',' operator in sed(1) and awk(1) (specifically, .. is like
awk's and ... like sed's) and was put into Perl for the benefit of
people used to those utilities.

Ben

--
"Faith has you at a disadvantage, Buffy."
"'Cause I'm not crazy, or 'cause I don't kill people?"
"Both, actually."
[b...@morrow.me.uk]

Uri Guttman

unread,
Jul 17, 2008, 1:33:00 PM7/17/08
to
>>>>> "BM" == Ben Morrow <b...@morrow.me.uk> writes:

BM> Quoth xho...@gmail.com:


>>
>> On the first point, I'm somewhat confused myself. I've never fully
>> understand what the flip-flop mode does, but I understand enough to avoid
>> accidentally using it, so my confusion is safely sequestered.

BM> It's designed for use with -n. Something like

BM> perl -ne'/foo/../bar/ and print'

and i have used it before with while(<FH>) loops. it isn't dedicated to
-n.

the flip flop op is just a bistable value. it starts out as false (it
returns a false value) until the left side expression evaluates to
true. then it returns true until the right side expression evaluates to
true. the it reverts to false and testing the left side again.

so it keeps track of its state between its evaluations. that is why it
is called flip flop (after the single bit hardware memory cell that
remembers its state). bistable is also a good name as it is stable in
two ways, true and false and needs a trigger (one side or the other
evaluating to true at the right time.

note that .. only evaluates one side or the other based on its current
state.

and it is called range even in scalar context because a (the most?)
common use is to select a range of lines from a stream. it even has a
builtin test against $. if either side is a literal number.

uri

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

xho...@gmail.com

unread,
Jul 17, 2008, 3:17:46 PM7/17/08
to
Ben Morrow <b...@morrow.me.uk> wrote:
> Quoth xho...@gmail.com:
> >
> > On the first point, I'm somewhat confused myself. I've never fully
> > understand what the flip-flop mode does, but I understand enough to
> > avoid accidentally using it, so my confusion is safely sequestered.
>
> It's designed for use with -n. Something like
>
> perl -ne'/foo/../bar/ and print'
>
> will print all the lines from 'foo' to 'bar', and

Oh yeah, I vaguely know what its purpose is, but all the things about
when each test is executed, and .. versus ..., and $. vs $_, and whether
the state is attached to one particular line of code or is global, it all
just made my eyes glaze over. So I decided I'd punt, and come back and
read the docs in more depth when/if I ever decided I actually needed to use
it.

Recently I wanted exactly the 3rd line after a given line (say, the one
containing "foo") over thousands of files.

I thought this would work:
fgrep -A3 -B-3 foo *.txt

Except fgrep stubbornly refuses to accept negative arguments to -B.
That almost tempted me to go back and read up on flip-flop again, but I
found another string that I could filter on (one that was unique to the
desired line out of the four lines returned by fgrep -A3 foo, but not
globally unique) before I actually bit the bullet.

Now that I have gone back and reread, I think this would work:

perl -lne '(/foo/../bar/) == 4 and print "$ARGV\t$_"' *.txt

But only because I found a string ("bar", here) that always occurs later
in each file to turn off the flip-flop, preparing it for the next file.

Hmm.

perl -lne '(/foo/..eof(ARGV)) == 4 and print "$ARGV\t$_"' *.txt

That seems to do it. Well, now I know.

Uri Guttman

unread,
Jul 17, 2008, 3:26:17 PM7/17/08
to
>>>>> "x" == xhoster <xho...@gmail.com> writes:

x> Ben Morrow <b...@morrow.me.uk> wrote:
>> Quoth xho...@gmail.com:
>> >
>> > On the first point, I'm somewhat confused myself. I've never fully
>> > understand what the flip-flop mode does, but I understand enough to
>> > avoid accidentally using it, so my confusion is safely sequestered.
>>
>> It's designed for use with -n. Something like
>>
>> perl -ne'/foo/../bar/ and print'
>>
>> will print all the lines from 'foo' to 'bar', and

x> Oh yeah, I vaguely know what its purpose is, but all the things about
x> when each test is executed, and .. versus ..., and $. vs $_, and whether
x> the state is attached to one particular line of code or is global, it all
x> just made my eyes glaze over. So I decided I'd punt, and come back and
x> read the docs in more depth when/if I ever decided I actually needed to use
x> it.

$_ has nothing to do with .. (it does matter if you use // as an
expression in your ..). the state of .. has to be local to the instance
of the op (not even the line of code). otherwise all hell would break
loose if two modules used .. at the same time. as for when the test
expressions are executed, it is easy to remember. left until true, then
right until true. all ... does is also test right immediately when left
becomes true so you can work on a range of one line.

x> Recently I wanted exactly the 3rd line after a given line (say, the one
x> containing "foo") over thousands of files.

x> I thought this would work:
x> fgrep -A3 -B-3 foo *.txt

x> Except fgrep stubbornly refuses to accept negative arguments to -B.
x> That almost tempted me to go back and read up on flip-flop again, but I
x> found another string that I could filter on (one that was unique to the
x> desired line out of the four lines returned by fgrep -A3 foo, but not
x> globally unique) before I actually bit the bullet.

x> Now that I have gone back and reread, I think this would work:

x> perl -lne '(/foo/../bar/) == 4 and print "$ARGV\t$_"' *.txt

x> But only because I found a string ("bar", here) that always occurs later
x> in each file to turn off the flip-flop, preparing it for the next file.

x> Hmm.

x> perl -lne '(/foo/..eof(ARGV)) == 4 and print "$ARGV\t$_"' *.txt

x> That seems to do it. Well, now I know.

look into ack, a perl version of grep with many perlish and developer
features. it may support that and if not, patches welcome! in fact
boston.pm is working on a rewrite of the ack main loop to make it faster
and cleaner.

0 new messages