roy%cybrspc@cs.umn.edu (Roy M. Silvernail) (11/19/90)
I'm a little confused about a detail regarding $#...
The manual (PL18, MS-DOS) says that you may find the length of an array
by evaluating $#arrayname. It goes on to explain that $# is actually the
index of the last element, and mentions that most arrays have a 0'th
element.
OK, given an array of 5 elements such as
@foo = ('1','2','3','4','5')
$#foo, in this case, will be 4, and therin lies the confusion. The array is
obviously 5 elements long. Wouldn't $# make more sense if it were to
point to the array element _past_ the last element assigned? (i.e. to
the null element past '5' in the above example) Then it could be used
directly as an indication of size, and as well, you could do
while (<instream>) {
@foo[$#foo] = $_;
}
to fill an array with an incoming stream of fields. (using @foo[$#foo +1]
works, but it's less intuitive to me)
It's possible that this has been addressed in later patch-levels, but
until PL41 comes around for DOS, I'm stuck at PL18. [ :-( ]
(not-quite-related question: how does one unlink() a file not in the
current directory? I've tried explicit pathnames with both / and \ as
separators, but to no avail)
Thanks in advance!
--
Roy M. Silvernail |+| roy%cybrspc@cs.umn.edu |+| #define opinions ALL_MINE;
main(){float x=1;x=x/50;printf("It's only $%.2f, but it's my $%.2f!\n",x,x);}
"This is cyberspace." -- Peter da Silva :--: "...and I like it here!" -- me
tchrist@convex.COM (Tom Christiansen) (11/20/90)
In article <LTaVs1w163w@cybrspc> roy%cybrspc@cs.umn.edu (Roy M. Silvernail) writes: >I'm a little confused about a detail regarding $#... > >Wouldn't $# make more sense if it were to >point to the array element _past_ the last element assigned? (i.e. to >the null element past '5' in the above example) Then it could be used >directly as an indication of size, and as well, you could do > >while (<instream>) { > @foo[$#foo] = $_; >} > >to fill an array with an incoming stream of fields. (using @foo[$#foo +1] >works, but it's less intuitive to me) It's also wrong -- you're using @ for $, which is a no-no, and tended to coredump earlier version of perl. I used to get bug reports on this one from my users all the time. Remember: when you want ONE value, use a $, and when you want many, use an @, as in: print $foo[1]; print @foo[1..3]; Anyway, while you could have written the above as: while (<INSTREAM>) { $foo[++$#foo] = $_; } That's not idiomatic perl. In <8225@jpl-devvax.JPL.NASA.GOV> Larry wrote: (yes, I do collect these.) Whenever you see subscripts in a Perl script, it's a pretty strong indication that things aren't being done the Perl Way. A cheaper way way to do this in perl would be while (<INSTREAM>) { push(@a, $_); } This runs in 70% the time of the previous example on my machine. This is nearly as fast as @a = <INSTREAM>; Which runs in 65% of the original time. Of course, you may not want to do this on small-memory machines and/or big files. --tom
roy%cybrspc@cs.umn.edu (Roy M. Silvernail) (11/21/90)
tchrist@convex.COM (Tom Christiansen) writes: > It's also wrong -- you're using @ for $, which is a no-no, and tended > to coredump earlier version of perl. And I learn Yet Another Perl of Wisdom... ;-) I'm going to learn this language yet! > In <8225@jpl-devvax.JPL.NASA.GOV> Larry wrote: (yes, I do collect these.) > > Whenever you see subscripts in a Perl script, it's a pretty strong > indication that things aren't being done the Perl Way. Just to cover all bases, then... is there a preferred Perl Way to access the last element in an array, besides $foo[$#foo]? > A cheaper way way to do this in perl would be > > while(<INSTREAM>) { > push(@a, $_); > } > > This runs in 70% the time of the previous example on my machine. > > This is nearly as fast as > > @a = <INSTREAM>; > > Which runs in 65% of the original time. Of course, you may not > want to do this on small-memory machines and/or big files. My application reads <INSTREAM>, processes each line separately, and (if the line qualifies) appends to an array. Thus, the push() call is just what I needed. Thanks, Tom, for your guidance. Until 'The Book' comes out, this newsgroup is my greatest asset in learning Perl. -- Roy M. Silvernail |+| roy%cybrspc@cs.umn.edu |+| #define opinions ALL_MINE; main(){float x=1;x=x/50;printf("It's only $%.2f, but it's my $%.2f!\n",x,x);} "This is cyberspace." -- Peter da Silva :--: "...and I like it here!" -- me
tchrist@convex.COM (Tom Christiansen) (11/22/90)
In article <69oys1w163w@cybrspc> roy%cybrspc@cs.umn.edu (Roy M. Silvernail) writes: |tchrist@convex.COM (Tom Christiansen) writes: |> In <8225@jpl-devvax.JPL.NASA.GOV> Larry wrote: (yes, I do collect these.) |> Whenever you see subscripts in a Perl script, it's a pretty strong |> indication that things aren't being done the Perl Way. | |Just to cover all bases, then... is there a preferred Perl Way to access |the last element in an array, besides $foo[$#foo]? If you just want to add or remove it, push and pop are pretty quick. If you want to muck with it in place, $foo[$#foo] is fine. Just don't do this: for ($i = $[; $i <= $#a; $i++) { $a[$i] = .... } when this is there begging to be used: foreach (@a) { # now access each element (by reference) as $_ # which is usually implicit anyway } --tom
allbery@NCoast.ORG (Brandon S. Allbery KB8JRR) (11/24/90)
As quoted from <LTaVs1w163w@cybrspc> by roy%cybrspc@cs.umn.edu (Roy M. Silvernail): +--------------- | $#foo, in this case, will be 4, and therin lies the confusion. The array is | obviously 5 elements long. Wouldn't $# make more sense if it were to | point to the array element _past_ the last element assigned? (i.e. to | the null element past '5' in the above example) Then it could be used | directly as an indication of size, and as well, you could do +--------------- Using $# usually means you aren't doing it the Perl way. To wit: +--------------- | while (<instream>) { | @foo[$#foo] = $_; | } +--------------- while (<instream> { push(@foo); } is faster and easier to read (once you're used to Perl, at least): "while you can get something from <instream>, push it onto array `foo'". +--------------- | It's possible that this has been addressed in later patch-levels, but | until PL41 comes around for DOS, I'm stuck at PL18. [ :-( ] +--------------- I think it's been as it is since Perl v1; as a result, it's a bit late to change it. I suspect a large number of scripts would break resoundingly. +--------------- | (not-quite-related question: how does one unlink() a file not in the | current directory? I've tried explicit pathnames with both / and \ as | separators, but to no avail) +--------------- Have you tried doubling the \? Remember that \ is meaningful to Perl as an escape character, so to get one into a string you must say something like '\\dos\\command.com'. (I assume the MS-DOS version of Perl doesn't use the old MS-DOS v1.25 calls!) ++Brandon -- Me: Brandon S. Allbery VHF/UHF: KB8JRR on 220, 2m, 440 Internet: allbery@NCoast.ORG Packet: KB8JRR @ WA8BXN America OnLine: KB8JRR AMPR: KB8JRR.AmPR.ORG [44.70.4.88] uunet!usenet.ins.cwru.edu!ncoast!allbery Delphi: ALLBERY
roy%cybrspc@cs.umn.edu (Roy M. Silvernail) (11/24/90)
tchrist@convex.COM (Tom Christiansen) writes: > Just don't do this: > > for ($i = $[; $i <= $#a; $i++) { > $a[$i] = .... > } > > when this is there begging to be used: > > foreach (@a) { > # now access each element (by reference) as $_ > # which is usually implicit anyway > } (got me another trick... thanks!) OK, now consider the following fragment: for($x=0;$x<$#foo;$x++) { @aa = split(/\\/,@foo[$x]); @bb = split(/\\/,@foo[$x+1]); # forward array reference $foo[$x] = '' if $bb[$#bb - 1] ne $aa[$#aa - 1]; } Is there a spiffy Perl Way to handle the forward reference in each iteration without the explicit variable-controlled loop? (or have I happened upon the occasional exception that demands the for() construct?) (I'll bet a lot of this is in 'The Book'... guess what I'm getting _me_ for Christmas) Thanks for the expert guidance. -- Roy M. Silvernail |+| roy%cybrspc@cs.umn.edu |+| #define opinions ALL_MINE; main(){float x=1;x=x/50;printf("It's only $%.2f, but it's my $%.2f!\n",x,x);} "This is cyberspace." -- Peter da Silva :--: "...and I like it here!" -- me
lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (11/25/90)
In article <Hg94s1w163w@cybrspc> roy%cybrspc@cs.umn.edu (Roy M. Silvernail) writes: : Is there a spiffy Perl Way to handle the forward reference in each : iteration without the explicit variable-controlled loop? (or have I : happened upon the occasional exception that demands the for() : construct?) In general you do this with a backward reference in Perl: $prev = ''; for (@foo) { if ($_ eq $prev) { } ... $prev = $_; } Apart from that, there's no special way to do it. Sometimes you just hafta use a normal for(). That's what it's there for, therefore. Larry
tchrist@convex.COM (Tom Christiansen) (11/26/90)
In article <Hg94s1w163w@cybrspc> roy%cybrspc@cs.umn.edu (Roy M. Silvernail) writes: |OK, now consider the following fragment: | |for($x=0;$x<$#foo;$x++) { | @aa = split(/\\/,@foo[$x]); | @bb = split(/\\/,@foo[$x+1]); # forward array reference | $foo[$x] = '' if $bb[$#bb - 1] ne $aa[$#aa - 1]; |} | |Is there a spiffy Perl Way to handle the forward reference in each |iteration without the explicit variable-controlled loop? (or have I |happened upon the occasional exception that demands the for() |construct?) Without trying to come up with something illegibly clever, direct indexing seems the easiest route if you're going to be checking more than the current element. I really do wish you wouldn't do things like this, though: | @aa = split(/\\/,@foo[$x]); This kind of thing makes me nervous. You see, split wants a scalar expression there in the second element. You just passed it a list of one element. While in this case, the difference is minimal, one of these days, it's going to come back to haunt you. Take my word on this one. For example, @a = ('red', 'green', 'blue'); @b[0] = @a; Now the zeroth element of @b is 'red', because you've got arrays on both sides of the assignment, so you got an array copy. Just because @b[0] is only one element long doesn't undo its listishness. Now, if you subscripted it the other way: $b[0] = @a; Then the zeroth element of @b is '3', that is, the length of @a, because you had a scalar context on the RHS of the assignment. Catch that? Moral of the story: when you want to talk about a single element, use $. When you might want more than one, use @. Try not to confuse a list that's one element long with a simple scalar value. If you don't follow this rule, it will someday come back to bite you where you're not looking, and you won't be happy. I promise. --tom
roy%cybrspc@cs.umn.edu (Roy M. Silvernail) (11/28/90)
tchrist@convex.COM (Tom Christiansen) writes: > I really do wish you wouldn't do things like this, though: > > | @aa = split(/\\/,@foo[$x]); > > This kind of thing makes me nervous. (ducking for cover....) Actually, I had grabbed that snippet, and _then_ fixed the references to scalars. (I did _so_ listen to you last time, Tom! :-) Thanks for keeping me honest! -- Roy M. Silvernail |+| roy%cybrspc@cs.umn.edu |+| #define opinions ALL_MINE; main(){float x=1;x=x/50;printf("It's only $%.2f, but it's my $%.2f!\n",x,x);} "This is cyberspace." -- Peter da Silva :--: "...and I like it here!" -- me