2

I want to get first or last element after map and grep operations over array. Using shift and pop operators with map and grep does not seem to work. Any suggestions? It works if I save result from map into array variable and do pop on that but I want to do that in one line.

:$ cat map.pl 
use strict;
use warnings;
my @arr = (1,2,3,4);
my $ele = pop ( map{10* $_ } @arr ) ;
print "\n element is $ele";
:$ perl map.pl
Not an ARRAY reference at map.pl line 4.
ikegami
  • 367,544
  • 15
  • 269
  • 518
Ameyj
  • 597
  • 1
  • 7
  • 16
  • 6
    In list context, `map` and `grep` produce lists, but `shift`/`unshift` and `push`/`pop` operate on arrays. Lists and arrays are not the same thing in Perl. You should be less worried about trying to do everything in one line, and more worried about writing code that's correct. – Matt Jacob Jul 12 '17 at 18:53
  • 1
    @MattJacob I thought that was a good answer to the question – ysth Jul 12 '17 at 20:13
  • A good link from a (good but deleted?) answer by Matt Jacob: [list vs array](https://stackoverflow.com/questions/14001741/what-is-the-difference-between-lists-and-arrays) – zdim Jul 12 '17 at 20:26

4 Answers4

7
map{10* $_ } @arr

produces a list whose elements are corresponding elements of @arr multiplied by 10. It does not produce an array. Therefore, you cannot pop anything out of it. You can access the last element though:

(map 10 * $_, @arr)[-1]

However, the map does not change @arr. If you want to do that,

 $_ *= 10 for @arr;

is more appropriate than map.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
7

The first argument to shift and pop must be an array (@NAME or @BLOCK), not a map or grep operator (which have nothing to do with arrays).

You could build an array from which to shift/pop.

my $first_ele = shift @{ [ map { 10 * $_ } @arr ] };           # If you want first
my $last_ele  = pop   @{ [ map { 10 * $_ } @arr ] };           # If you want last

But that's very wasteful. You could avoid the array creation by using a list assignment or a list slice.

my ($first_ele) = map { 10 * $_ } @arr;                        # If you want first
my $first_ele = ( map { 10 * $_ } @arr )[0];                   # If you want first
my $last_ele  = ( map { 10 * $_ } @arr )[-1];                  # If you want last
my ($first_ele, $last_ele) = ( map { 10 * $_ } @arr )[0, -1];  # If you want both

But that's still wasteful. There's no need to multiply all the elements when you only want the product of last one. The following makes far more sense:

my $first_ele = 10 * $arr[0];                                  # If you want first
my $last_ele  = 10 * $arr[-1];                                 # If you want last
my ($first_ele, $last_ele) = map { 10 * $_ } @arr[0, -1];      # If you want both
ikegami
  • 367,544
  • 15
  • 269
  • 518
3

In list context, map and grep produce lists, but shift/unshift and push/pop operate on arrays. Lists and arrays are not the same thing in Perl. You should be less worried about trying to do everything in one line, and more worried about writing code that's correct.

Matt Jacob
  • 6,503
  • 2
  • 24
  • 27
1

First or last? For first you can use

    use strict;
    use warnings;
    my @arr = (1,2,3,4);
    my ($ele) = map{10* $_ } @arr;
    print "\n element is $ele\n\n";
Fritz
  • 359
  • 3
  • 9
  • Seems the OP wants to be able to do both as they mention both first and last, and shift and pop. I adjusted the OP to make that clear. – ikegami Jul 12 '17 at 21:23