Mapping: can we use something instead of a conditional operator

So, I understand what the following code does and why it works, but there seems to be a different way for this:

my @squares = map { $_ > 5 ? ($_ * $_) : () } @numbers; 

Is there a way we can say:

 my @squares = map { if ($_ > 5) then ($_ * $_) } @numbers; 

Or do we need to have a β€œrule” for each record, that is else return ()?

+4
source share
2 answers

Amon gave you a lot of information, but actually did not answer the question. Equivalent

 map { $_ > 5 ? ($_ * $_) : () } 

using if instead of conditional operator

 map { if ($_ > 5) { $_ * $_ } else { () } } 

It is not possible for a map expression to return a value. It returns the last expression. If you delete the else clause, this expression is a comparison, so it will look like what you did

 map { if ($_ > 5) { $_ * $_ } else { $_ > 5 } } 

although $_ > 5 only starts once, so I think it's closer to

 map { ($_ > 5) && ($_ * $_) } 

So yes, you should have a rule for each entry, in the sense that this is not possible.

+5
source

For this to work, the map block must return an empty list of unwanted elements. Although the code was rewritten using grep ,

 my @squares = map { $_**2 } grep { $_ > 5 } @numbers; 

it loses a lot of elegance.

If we do not specify the return value of else , if , apparently, implicitly passes a false value:

 say $_+0 for map{ if($_>5){$_**2} } 3..7; # 0 # 0 # 0 # 36 # 49 

which is useless for our purpose.

But we can always write a filtering map that returns the value of our block, or an empty list if it was false:

 sub mapgrep (&@) { my $cb = shift; map { local $_ = $_; $cb->($_) || () } @_; } my @squares = mapgrep { $_**2 if $_ > 5 } @numbers; 

However, this depends on the side effect that the conditional returns the value of the condition, unless this condition is otherwise handled. I do not see where this is explicitly documented.

(Note: Perl does not have the then keyword).

+5
source

Source: https://habr.com/ru/post/1480315/


All Articles