Re: Getting range from N..end with list slice
by BrowserUk (Patriarch) on Nov 27, 2010 at 13:57 UTC
|
$s = join'', 'a'..'z';;
@bits = do{ local @_ = split'', $s; @_[3..$#_]};;
print @bits;;
d e f g h i j k l m n o p q r s t u v w x y z
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |
Re: Getting range from N..end with list slice
by jwkrahn (Abbot) on Nov 27, 2010 at 15:16 UTC
|
$ perl -le'
use warnings;
use strict;
use 5.10.0;
my $x = "a b c d e f g h";
my @set = splice @{ [ split " ", $x ] }, 3;
print "@set";
'
d e f g h
Update:
$ perl -le'
use warnings;
use strict;
use 5.10.0;
my $x = "a b c d e f g h";
my @set = split " ", ( split " ", $x, 4 )[ -1 ];
print "@set";
'
d e f g h
| [reply] [d/l] [select] |
Re: Getting range from N..end with list slice
by BrowserUk (Patriarch) on Nov 27, 2010 at 15:12 UTC
|
Or, if efficiency is sufficient concern to override clarity:
my @bits = sub{ @_[3..$#_] }->( split'', $s );
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |
Re: Getting range from N..end with list slice
by CountZero (Bishop) on Nov 27, 2010 at 14:51 UTC
|
This is all I can find in Perl51000delta about list slices:Subscripts of slices
You can now use a non-arrowed form for chained subscripts after a list slice, like in:
({foo => "bar"})[0]{foo}
This used to be a syntax error; a -> was required.
CountZero A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James
| [reply] [d/l] [select] |
Re: Getting range from N..end with list slice
by JavaFan (Canon) on Nov 27, 2010 at 12:04 UTC
|
(undef, undef, undef, @set) = (split ' ', $x);
| [reply] [d/l] |
|
|
my $x = "a b c d e f g h";
my @set = (split /\s+/, $x);
splice(@set,0,3);
print "@set\n"; #prints d e f g h
| [reply] [d/l] |
|
|
Personally, I wouldn't fret on it. If the point is you want to do it all in one statement:
my @set = (split /\s+/, $x)[3 .. -1 + split /\s+/, $x];
But that splits twice. | [reply] [d/l] |
Re: Getting range from N..end with list slice
by ambrus (Abbot) on Nov 27, 2010 at 18:12 UTC
|
Just a note: take care with using grep { defined } that way, for it might have odd side effects:
$ perl -wE '@x = qw"a b c d e f g h"; say 0+@x; say join ":", grep { d
+efined } @x[4 .. 99]; say 0+@x;'
8
e:f:g:h
100
$
| [reply] [d/l] [select] |
|
|
>perl -E"@a[4..99] = (); say 0+@a;"
100
>perl -E"for (@a[4..99]) {} say 0+@a;"
100
>perl -E"sub {}->(@a[4..99]); say 0+@a;"
100
>perl -E"grep 1, @a[4..99]; say 0+@a;"
100
| [reply] [d/l] |
Re: Getting range from N..end with list slice
by ikegami (Patriarch) on Nov 27, 2010 at 20:41 UTC
|
".." is the range operator. It can create a list of ascending numbers. You need to know the start and end of the range. In general, there's nothing you can count to determine the start and end of the range when doing a list slice.
And here's the doozy. This probably isn't documented, but in a list slice, the index expression is evaluated before the list expression. This means you need to know how many elements split will return before split is even called. That means you need to find an alternate code arrangement.
Some solutions:
(undef, undef, undef, my @set) = split /\s+/, $x;
my @set = split /\s+/, $x;
splice(@set, 0, 3);
my @set = sub { @_[3..$#_] }->( split /\s+/, $x );
The last one hasn't been mentioned yet.
Update: Changed HTML coding so that users of "Enforce proper nesting" could see the DELeleted text.
| [reply] [d/l] [select] |
|
|
And here's the doozy. This probably isn't documented, but in a list slice, the index expression is evaluated before the list expression. This means you need to know how many elements split will return before split is even called. That means you need to find an alternate code arrangement.
Thanks Ikegami! That was exactly the sort of info that I was hoping to find out in the absence of a "sure, its easy..just do X" answer). This is as close as one can get to proving a negative. So unless other info is forthcoming, I would say that my friend is mistaken because this claimed new feature just can't be implemented due to the way Perl evaluates the expression. And yes this was a trivia question. For me personally, I think the splice() solution is the winner in terms of clarity and performance.
| [reply] |
|
|
>perl -MO=Concise,-exec -e"(LIST_EXPR)[INDEX_EXPR]"
1 <0> enter
2 <;> nextstate(main 1 -e:1) v:{
3 <0> pushmark s
4 <$> const[PV "INDEX_EXPR"] s/BARE
5 <0> pushmark s
6 <$> const[PV "LIST_EXPR"] s/BARE
7 <2> lslice vK/2
8 <@> leave[1 ref] vKP/REFC
-e syntax OK
Or a more à propos example,
>perl -MO=Concise,-exec -e"(split)[$x..$y]"
1 <0> enter
2 <;> nextstate(main 1 -e:1) v:{
3 <0> pushmark s
4 <|> range(other->5)[t5] lK/1 <--------
5 <#> gvsv[*y] s
6 <1> flop lK
goto 7
e <#> gvsv[*x] s
f <1> flip[t6] lK
7 <0> pushmark s
8 </> pushre(/" "/) s*/64
9 <#> gvsv[*_] s
a <$> const[IV 0] s
b <@> split[t2] lK <--------
c <2> lslice vK/2
d <@> leave[1 ref] vKP/REFC
-e syntax OK
Now, I suspect the relative order in which the expressions are evaluated is arbitrary. It could be changed if it would be deemed useful to evaluate them in the other order.
| [reply] [d/l] [select] |
|
|
| [reply] |
|
|
The OP found great value in my post, so your poor opinion of it doesn't count for much to me.
| [reply] |
Re: Getting range from N..end with list slice
by ikegami (Patriarch) on Nov 28, 2010 at 04:37 UTC
|
$a[-1] # last element
$a[-2] # second-last element
This is much older than 5.10. It also works on slices
@a[-2, -1] # second-last and last element
But you have to keep in mind that ".." has nothing to do with slices. If the LHS is greater than the RHS, it returns an empty list.
>perl -E"@a = qw( a b c d e f ); say for @a[4..-1]"
>perl -E"@a = qw( a b c d e f ); say for @a[-3..-1]"
d
e
f
>perl -E"@a = qw( a b c d e f ); say for @a[-1..-3]"
>perl -E"@a = qw( a b c d e f ); say for @a[reverse -3..-1]"
f
e
d
>perl -E"@a = qw( a b c d e f ); say for reverse @a[-3..-1]"
f
e
d
| [reply] [d/l] [select] |
|
|
I also played around with negative indicies, but the problem is that say with [-3..-1], in general we don't know what this -3 value is supposed to be because it is counted backwards from the right. All we know is that we don't want [0,1,2](counted from the left).
This >perl -E"@a = qw( a b c d e f ); say for @a[4..-1]" would work except for that pesky LHS > RHS returns empty list rule! My friend may be thinking that there is some new syntax like: @a[4..eol], where "eol" is some stand-in for the largest positive index whatever that happens to be. Or alternately some way to determine, not the value at [-1], but the positive index that it would correspond to.
I also wondered if there was some sort of new syntax that would express the idea of "give me everything except the stuff at these particular indicies...", but was unable to find anything like that.
| [reply] [d/l] [select] |
|
|
>perl -wMstrict -le
"my @ra = qw(a b c d e f g h);
my $i = 4;
print qq{'$_'} for @ra[$i - @ra .. -1];
"
'e'
'f'
'g'
'h'
| [reply] [d/l] |
|
|
|
|