Perl PDL 中 R 的 ifelse 的等价物是什么

What's the equivalent of R's ifelse in Perl PDL

我是 PDL 新手。 R 的 ifelse() 方法可以进行条件元素选择。例如,

x <- c(1,2,3,4)
ifelse(x%%2, x, x*2)
# [1] 1 4 3 8

有人知道如何在 PDL 中执行此操作吗?我知道你可以像下面那样做,但是有没有更好的方法?

pdl(map { $_ % 2 ? $_ : $_*2 } @{$x->unpdl} )

$x ? $y : $z好?不是我的想法,但这是风格和品味的问题

sub ifelse {
    my ($x,$y,$z) = @_;

    $x ? $y : $z ;
    if($x){$y}else{$z} ;
    [$y,$z]->[!$x] ;
    [$z,$y]->[!!$x] ;
    ($x && $y) || $z ;        # valid only if $y is always true
    (!$x && $z) || $y ;       # valid only if $z is always true
}
#! /usr/bin/perl
use warnings;
use strict;

use PDL;

my $x     = 'PDL'->new([1, 2, 3, 4]);
my $where = ! ($x % 2);               # [0 1 0 1]
my $y     = $x * ($where + 1);
print $y;                             # [1 4 3 8]

或者,很快

my $y = $x * ( 2 - $x % 2 );

我自己回答问题。可以是这样的,

use PDL;                                                                      

sub ifelse {                                                                  
    my ( $test, $yes, $no ) = @_;                                             

    $test = pdl($test);                                                       
    my ( $ok, $nok ) = which_both($test);                                     

    my $rslt = zeros( $test->dim(0) );                                        

    unless ( $ok->isempty ) {                                                 
        $yes = pdl($yes);                                                     
        $rslt->slice($ok) .= $yes->index( $ok % $yes->dim(0) );               
    }                                                                         
    unless ( $nok->isempty ) {                                                
        $no = pdl($no);                                                       
        $rslt->slice($nok) .= $no->index( $nok % $no->dim(0) );               
    }                                                                         
    return $rslt;                                                             
}                                                                             

my $x = pdl( 1, 2, 3, 4 );                                                    
say ifelse( $x % 2, $x, $x * 2 );       # [1 4 3 8]                                             
say ifelse( $x % 2, 5, sequence( 3 ) ); # [5 1 5 0]                                      
say ifelse( 42, $x, $x * 2 );           # [1]

在 PDL 中,此类问题的一般解决方案可能涉及切片等。查看 PDL (2.077) 的最新发行说明,其中有一个新的 where_both,我想起了这个问题(披露:我是当前的维护者)。虽然您的具体问题仅涉及更改偶数的值,但我还将展示将赔率加 2 的情况:

my ($odd, $even) = where_both($x, $x % 2);
$odd += 2, $even *= 2; # the "," form is just a flourish, it could be 2 lines

它是高效的,以适当的 PDL 风格,因为 $x 的扫描只发生一次(你不会惊讶地发现它也在幕后使用 which_both),并且突变只看相关位的切片。 与您的代码非常相似,但它被捕获到一个小的 widely-reusable 函数中。 (我写它是为了将 TriD EuclidAxes 的东西从使用 Perl for-loops 变成实际使用 ndarrays,如果你感兴趣的话)