Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:
why does
$_='something,something else';
@_ = shift split /,/;
yield this error: Not an ARRAY reference
I sorta get that shift is an operator that changes its arg, but doesnt "return" the result. So, why does this ALSO not work:
$_='something,something else';
shift ( @_ = split /,/ );
(all result in the same error).
It seems like "some" construct of shifting a split should work? Help please Blessed Ones! Surely the LAST one should be an ARRAY!?
It "seems" natural that Larry would have intended to allow cascading operators like these?
Re: why can't I shift a split?
by ikegami (Patriarch) on Aug 25, 2022 at 15:36 UTC
|
shift requires an array (@NAME, @BLOCK, EXPR->@* and similar).
You want a list slice (( LIST )[ INDEXES ]).
Specifically,
( split( /,/, $_, 2 ) )[ 0 ]
If you are assigning the result to a scalar, you can also use
my ( $first ) = split( /,/, $_, 2 );
Using 2 for split's third operand isn't required; it's an optimization. There's no reason to continue splitting after the first split. | [reply] [d/l] [select] |
Re: why can't I shift a split?
by Tux (Canon) on Aug 25, 2022 at 15:43 UTC
|
To me, it is not clear what you want at all. Do you want the result of the split excluding the first element in @_? Or do you want @_ only hold the first element and discard the rest?
$ perl -E'$a="a,b,c,d";(undef,@_)=split/,/,$a;say "@_"'
b c d
$ perl -E'$a="a,b,c,d";@_=(split/,/,$a,2)[0];say "@_"'
a
Enjoy, Have FUN! H.Merijn
| [reply] [d/l] [select] |
Re: why can't I shift a split?
by kcott (Archbishop) on Aug 25, 2022 at 15:27 UTC
|
Take a look at shift.
It says "shift ARRAY", not "shift LIST".
Look down to the nextsecond paragraph where it talks about an experimental feature that's been removed.
I'm guessing the version of Perl you're using is >=v5.14 and <v5.24:
so it's trying to use that experimental feature but failing because "( @_ = split /,/ )"
is not an array, nor does it evaluate to an arrayref.
You can try the following with your version of Perl.
I don't have a version earlier the v5.30, so I get:
$ perl -MO=Deparse -e 'shift ( @_ = split /,/ )'
Experimental shift on scalar is now forbidden at -e line 1, near "/,/
+)
"
-e had compilation errors.
shift(@_ = split(/,/, $_, 0));
| [reply] [d/l] [select] |
|
shift @{ @_ = split /,/; \@_ }
There's no need to use named array, though.
shift @{[ split /,/ ]}
But I'd use a list slice, as shown in my reply to the OP.
| [reply] [d/l] [select] |
Re: why can't I shift a split? (List vs Array)
by LanX (Saint) on Aug 25, 2022 at 23:25 UTC
|
The fundamental problem here is that lists and arrays are two different things. That's a FAQ
Lists are temporary data sequences which can't be changed!
But Arrays are variable(s) with @sigils and they are changed.
Shift can only operate on arrays, because they are shortened afterwards.
Once you've understood this...
> why can't I shift a split?
Because split returns a list!
Unless you assign it to an array it can't be shifted.
Addendum
Others have shown solutions with (lists)[slices] which work similar to @array[slices] . That's only possible because a slice doesn't change its object, unlike shift.
Further reading
| [reply] [d/l] [select] |
|
Rolf yes, I know that- but it should be EZ to coerce a list into an array?
| [reply] |
|
> should be EZ to coerce a list into an array
sure:
DB<2> p shift @{[42..59]}
42
or
DB<3> $shift = sub { shift @{$_[0]} }
DB<4> p [42..59]->$shift
42
but it doesn't make sense since the resulting shortened array is destroyed right away.
Using a list slice is the logical° and easiest approach, without wasting operations.
DB<5> p (42..59)[0]
42
compare an array slice which wastes resources again, by allocating an array in memory which is destroyed again.
DB<6> p [42..59]->[0]
42
°) and "implementing" pop list is symmetrical (42..59)[-1] | [reply] [d/l] [select] |
Re: why can't I shift a split?
by afoken (Chancellor) on Aug 25, 2022 at 15:42 UTC
|
$_='something,something else';
@_ = shift split /,/;
So you want to split at comma, but get only the first part?
use strict;
use warnings;
use v5.12;
(my $first,undef)=split /,/,'foo,bar',2;
say $first;
Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
| [reply] [d/l] [select] |
Re: why can't I shift a split?
by harangzsolt33 (Chaplain) on Aug 26, 2022 at 01:09 UTC
|
It's funny, I was trying to explain why it's not working, and I got really confused myself! LOL Here's what I began to write:
When you do shift split, the shift() function not only returns the first element of an array, but it also tries to REMOVE that element from an array, which it must be able to do. Demo:
#!/usr/bin/perl
use strict;
use warnings;
my @A = (234, 405, 55, 1900);
print "\n", shift(@A); # Prints 234
#print "\n", shift(234, 4, 55, 1900); # Error: Can't overwrite
+the array, because it's fixed.
#print "\n", shift( split(/\+/, '12+34+56+78') ); # Error: Can't over
+write the array, because it's fixed.
my $X = 3;
print "\n", INCREMENT($X); # Prints 4.
#print "\n", INCREMENT(3); # Error: Can't overwrite 3, because it's
+ fixed.
print "\nNOW: $X"; # Prints 4. No error.
print "\n", INCREMENT( $X + 3 ); # Prints 8. No error.
print "\nTHEN: $X"; # Prints 4. No error.
#print "\n", shift( @A, split(/\+/, '12+34+56+78') ); # Error. Can't
+do this.
# Kind of weird. That's not what I expected. :P
exit;
sub INCREMENT { ++$_[0]; }
See also: lvalue | [reply] [d/l] |
|
johngg@aleatico:~$ perl -Mstrict -Mwarnings -E '
my @arr = ( 234, 405, 55, 1900 );
say shift @arr;
say sub { shift }->( 234, 405, 55, 1900 );
$_ = q{ab,ce ef};
say sub { shift }->( split m{,} );'
234
234
ab
I hope this is helpful.
Update: Corrected typo, s{on (?=by default)}{}.
| [reply] [d/l] [select] |
Re: why can't I shift a split?
by misterperl (Pilgrim) on Aug 25, 2022 at 14:27 UTC
|
Oh drat I wasn't logged in! I also tried this fugly one: $_='something,something else';
@_ = shift @ {split /,/ };
which is OK syntax wise, but results in "undef".
| [reply] [d/l] |
|
$_='something,something else';
@_ = shift @ {[split /,/ ]};
does work.
| [reply] [d/l] |
|
@_ = split /,/,join "\n",$myscalar
I was trying to do something similar with shift.. I also triedshift @_ = split /,/,join "\n",$myscalar
Which I thought had the best chance. Mr TVVALUT has a solution I'll try... I recognize the list/ARRAY difference which is why I was trying various "@{}" constructs to coerce it.
Seems like if I can split a join, then I ought to be able to shift a split!
TY all!
| [reply] [d/l] [select] |
|
|
|
|
|
|