是否有一个紧凑的Perl操作来切割阵列中的替代元素?

Rhu*_*arb 15 syntax perl

如果我myarray在Python中有一个数组,我可以使用切片表示法

myarray[0::2]
Run Code Online (Sandbox Code Playgroud)

仅选择偶数索引元素.例如:

>>> ar = [ "zero", "one", "two", "three", "four", "five", "six" ]
>>> ar [ 0 : : 2 ]
['zero', 'two', 'four', 'six']
Run Code Online (Sandbox Code Playgroud)

Perl中有类似的设施吗?

谢谢.

bri*_*foy 23

Perl数组切片位于@数组名称的前面,然后是您想要的索引列表:

 @array[@indices];
Run Code Online (Sandbox Code Playgroud)

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

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

如果您使用的是PDL,那么有很多很好的切片选项.


raf*_*afl 21

有阵列切片:

my @slice = @array[1,42,23,0];
Run Code Online (Sandbox Code Playgroud)

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

my @list = $x .. $y
Run Code Online (Sandbox Code Playgroud)

有一种方法可以从列表中构建新列表:

my @new = map { $_ * 2 } @list;
Run Code Online (Sandbox Code Playgroud)

并且有一种方法可以获得数组的长度:

my $len = $#array;
Run Code Online (Sandbox Code Playgroud)

放在一起:

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

当然,不如python等同,但是它做同样的工作,你当然可以把它放在一个子程序中,如果你经常使用它并希望从一些写作中省去自己.

还有一些东西可以允许以更自然的方式写出来List::AllUtils.


Eri*_*rom 11

我在CPAN上编写了模块List :: Gen,提供了另一种方法:

use List::Gen qw/by/;

my @array = qw/zero one two three four five six/;

my @slice = map {$$_[0]} by 2 => @array;
Run Code Online (Sandbox Code Playgroud)

by分区@array成两个元素的组,并返回数组引用的数组. map然后获取此列表,因此$_地图中的每个都将是一个数组引用. $$_[0](也可以写$_->[0])然后抓住by创建的每个组的第一个元素.

或者,使用内部使用的mapn功能by:

use List::Gen qw/mapn/;

my @slice = mapn {$_[0]} 2 => @array;   
Run Code Online (Sandbox Code Playgroud)

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

use List::Gen qw/by gen/;

my $slicer = gen {$$_[0]} by 2 => @array;
Run Code Online (Sandbox Code Playgroud)

$slicer现在是一个惰性列表(数组引用),它将根据需要生成它的切片,而不处理您没有要求的任何内容. $slicer如果你不想将它用作数组引用,也有一堆访问器方法.


Eth*_*her 9

我将在两个步骤中完成此操作:首先生成所需的索引,然后使用切片操作来提取它们:

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

一步一步,多数民众赞成:

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


yst*_*sth 7

Perl 6会大大改进,但(到目前为止?)Perl 5的切片功能非常有限:你必须明确指定你想要的索引,而且它不能是开放式的.

所以你必须这样做:

@ar = ( "zero", "one", "two", "three", "four", "five", "six" );
print @ar[ grep $_ % 2 == 0, 0..$#ar ]
Run Code Online (Sandbox Code Playgroud)


dra*_*tun 5

使这个更美丽的一种方法是将它包装成类似的东西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;
Run Code Online (Sandbox Code Playgroud)

这是你如何定义这些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;
}
Run Code Online (Sandbox Code Playgroud)

/ I3az /