Question in Perl Arrays

Y

Yogi

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,
 
G

Gunnar Hjalmarsson

Yogi said:
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.
 
Y

Yogi

Yogi said:
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.

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
 
R

RedGrittyBrick

Yogi said:
Yogi said:
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.

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.

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.
 
M

Mirco Wahab

RedGrittyBrick said:
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.
 
Y

Yogi

RedGrittyBrick said:
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.

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,
 
Y

Yogi

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.
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?

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

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

RedGrittyBrick

Mirco said:
RedGrittyBrick said:
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
...

TFTC
 
M

Mirco Wahab

RedGrittyBrick said:
Mirco said:
RedGrittyBrick said:
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.
 
R

RedGrittyBrick

Mirco said:
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
 
X

xhoster

Yogi said:
.....

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.
 
B

Ben Morrow

Quoth (e-mail address removed):
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
 
U

Uri Guttman

BM> Quoth (e-mail address removed):
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
 
X

xhoster

Ben Morrow said:
Quoth (e-mail address removed):

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.

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.
 
U

Uri Guttman

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.

uri
 
D

David Combs

BM> Quoth (e-mail address removed):

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

What about when there's three dots, "..."?

(This thread is shaping up to be a pretty good doc
on flip=flop, with contexts.)

THANKS!

David
 
B

Ben Morrow

Quoth (e-mail address removed) (David Combs):
What about when there's three dots, "..."?

I think perlop is pretty clear on that point, at least:

| [".."] can test the right operand and become false on the same
| evaluation it became true (as in awk), but it still returns true once.
| If you don’t want it to test the right operand till the next
| evaluation, as in sed, just use three dots ("...") instead of two. In
| all other regards, "..." behaves just like ".." does.

so given the input

FOOBAR
BAZ
BAR
QUUX

this

perl -ne'print if /FOO/../BAR/'

will print

FOOBAR

only, whereas this

perl -ne'print if /FOO/.../BAR/'

will print

FOOBAR
BAZ
BAR

that is, it ignores the fact that the 'start matching' line is also a
valid 'stop matching' line. That is the only difference between the two.

Ben
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,175
Messages
2,570,946
Members
47,497
Latest member
PilarLumpk

Latest Threads

Top