Is there a compact Perl operation to slice alternate elements from an array?

后端 未结 10 918
我在风中等你
我在风中等你 2020-12-15 20:37

If I have an array myarray in Python, I can use the slice notation

myarray[0::2]

to select only the even-indexed elements. For

相关标签:
10条回答
  • 2020-12-15 21:34

    I've written the module List::Gen on CPAN that provides an alternative way to do this:

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

    by partitions @array into groups of two elements and returns an array of array references. map then gets this list, so each $_ in the map will be an array reference. $$_[0] (which could also be written $_->[0]) then grabs the first element of each group that by created.

    Or, using the mapn function which by uses internally:

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

    Or, if your source list is huge and you may only need certain elements, you can use List::Gen's lazy lists:

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

    $slicer is now a lazy list (an array ref) that will generate it's slices on demand without processing anything that you didn't ask for. $slicer also has a bunch of accessor methods if you don't want to use it as an array ref.

    0 讨论(0)
  • 2020-12-15 21:34

    If you don't care about the order, and if the odd-numbered elements of the list are unique, you can concisely convert the array to a hash and take the values:

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

    (No, this is not a serious answer)

    0 讨论(0)
  • 2020-12-15 21:36

    Another way would be by using 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 
    
    0 讨论(0)
  • 2020-12-15 21:42

    There's array slices:

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

    There's a way to to generate lists between $x and $y:

    my @list = $x .. $y
    

    There's a way to build new lists from lists:

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

    And there's a way to get the length of an array:

    my $len = $#array;
    

    Put together:

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

    Granted, not quite as nice as the python equivalent, but it does the same job, and you can of course put that in a subroutine if you're using it a lot and want to save yourself from some writing.

    Also there's quite possibly something that'd allow writing this in a more natural way in List::AllUtils.

    0 讨论(0)
提交回复
热议问题