代码之家  ›  专栏  ›  技术社区  ›  Rhubbarb

是否有一个紧凑的Perl操作来从数组中分割备用元素?

  •  15
  • Rhubbarb  · 技术社区  · 14 年前

    如果我有阵列 myarray

    myarray[0::2]
    

    只选择偶数索引元素。例如:

    >>> ar = [ "zero", "one", "two", "three", "four", "five", "six" ]
    >>> ar [ 0 : : 2 ]
    ['zero', 'two', 'four', 'six']
    

    Perl中是否有类似的功能?

    10 回复  |  直到 14 年前
        1
  •  21
  •   Svante    14 年前

    有数组切片:

    my @slice = @array[1,42,23,0];
    

    有一种方法可以在$x和$y之间生成列表:

    my @list = $x .. $y
    

    有一种方法可以从列表中生成新列表:

    my @new = map { $_ * 2 } @list;
    

    有一种方法可以得到数组的长度:

    my $len = $#array;
    

    my @even_indexed_elements = @array[map { $_ * 2 } 0 .. int($#array / 2)];
    

    当然,虽然不如python的同类程序好,但它做的是相同的工作,如果您经常使用它,并且希望节省一些写作时间,那么您当然可以将其放在子例程中。

    List::AllUtils

        2
  •  23
  •   brian d foy    14 年前

    @ 在数组名称前面,然后是所需的索引列表:

     @array[@indices];
    

    没有一个内置的语法来选择倍数,但并不难。使用grep()生成所需的索引列表:

     my @array = qw( zero one two three four five six );
     my @evens = @array[ grep { ! ($_ % 2) } 0 .. $#array ];
    

    PDL ,有很多不错的切片选项。

        3
  •  11
  •   Eric Strom    14 年前

    我已经写了模块 List::Gen 在提供了另一种方法来实现这一点的CPAN上:

    use List::Gen qw/by/;
    
    my @array = qw/zero one two three four five six/;
    
    my @slice = map {$$_[0]} by 2 => @array;
    

    by 分区 @array 分成两个元素的组并返回数组引用数组。 map $_ 在映射中将是数组引用。 $$_[0] (也可以写成 $_->[0] 通过

    mapn 功能 通过 内部使用:

    use List::Gen qw/mapn/;
    
    my @slice = mapn {$_[0]} 2 => @array;   
    

    或者,如果源列表很大,并且可能只需要某些元素,则可以使用 List::Gen 的懒惰列表:

    use List::Gen qw/by gen/;
    
    my $slicer = gen {$$_[0]} by 2 => @array;
    

    $slicer 现在是一个惰性列表(数组引用),它将按需生成切片,而不处理任何您没有要求的内容。 $切片器 如果不想将其用作数组引用,还可以使用一系列访问器方法。

        4
  •  9
  •   Ether    14 年前

    我将分两步进行:首先生成所需的索引,然后使用切片操作提取它们:

    @indices = map { $_ * 2 } (0 .. int($#array / 2));
    my @extracted = @array[@indices];
    

    一步一步,就是:

    • 生成从0到数组最后一个元素除以2的整数列表
    • 将每个整数乘以2:现在我们有从0到最后一个元素的索引的偶数
    • 从原始数组中提取这些元素
        5
  •  7
  •   ysth    14 年前

    所以你必须:

    @ar = ( "zero", "one", "two", "three", "four", "five", "six" );
    print @ar[ grep $_ % 2 == 0, 0..$#ar ]
    
        6
  •  5
  •   draegtun    14 年前

    更漂亮 是用类似的东西把它包起来 autobox .

    例如使用 autobox::Core :

    use autobox::Core;
    my @ar = qw/zero one two three four five six/;
    
    # you could do this
    @ar->slice_while( sub{ not $_ % 2 } );
    
    # and this
    @ar->slice_by(2);
    
    # or even this
    @ar->evens;
    

    以下是定义这些autobox方法的方法:

    sub autobox::Core::ARRAY::slice_while {
        my ($self, $code) = @_;
        my @array;
    
        for (my $i = 0; $i <= $#{ $self }; $i++) {
            local $_ = $i;
            push @array, $self->[ $i ] if $code->();
        }
    
        return wantarray ? @array : \@array;
    }
    
    sub autobox::Core::ARRAY::slice_by {
        my ($self, $by) = @_;
        my @array = @$self[ map { $_ * $by } 0 .. int( $#{$self} / $by )];
        return wantarray ? @array : \@array;
    }
    
    sub autobox::Core::ARRAY::evens {
        my $self  = shift;
        my @array = $self->slice_by(2);
        return wantarray ? @array : \@array;
    }
    

        7
  •  4
  •   mob    14 年前

    如果您不关心顺序,并且列表的奇数元素是唯一的,那么您可以简单地将数组转换为散列并获取 values

    @even_elements = values %{{@array}};
    @odd_elements = keys %{{@array}};
    

    (不,这不是一个严肃的回答)

        8
  •  2
  •   Nikhil Jain    14 年前

    另一个 将通过使用 grep

    my @array = qw( zero one two three four five six );
    
    print map { "$_ " } @array[grep { !($_ & 1) } 0 .. $#array];  #even
    Output:zero two four six
    
    print map { "$_ " } @array[grep { ($_ & 1) } 0 .. $#array];  #odd
    Output:one three five 
    
        9
  •  1
  •   user2510677    11 年前

    如果您不介意使用$|的模糊功能,可以执行以下操作:

    {
        local $|; # don't mess with global $|
        @ar = ( "zero", "one", "two", "three", "four", "five", "six" );
        $| = 0;
        @even = grep --$|, @ar;
        $| = 1;
        @odd = grep --$|, @ar;
        print "even: @even\\n";
        # even: zero two four six
        print "odd: @odd\\n";
        # odd: one three five
    }
    

     { local $|=0; @even = grep --$|, @ar; }
    

    基本上,--$|触发器介于0和1之间(尽管--通常会递减一个数值),因此grep每隔一次就会看到一个“true”值,从而导致它返回以$|的初始值开始的每个其他项。请注意,必须以0或1开头,而不是以任意索引开头。

        10
  •  1
  •   Jiri Klouda    9 年前

    sub even { my $f=0; return grep {++$f%2} @_; }
    sub odd { my $f=1; return grep {++$f%2} @_; }