Есть ли способ захватить фрагмент в конец анонимного массива в Perl? - PullRequest
13 голосов
/ 02 ноября 2010

Так что это заставляет меня сходить с ума последние полчаса.Есть ли способ для меня, чтобы захватить срез массива до конца анонимного массива?Я пробовал:

(split(' ',$test_line))[1..$#_]

, и я пробовал: (split(' ',$test_line))[1..-1]

, но, к сожалению, ни одна из этих работ.Я действительно не хочу создавать дополнительную временную переменную для промежуточного массива (который мне не нужен).И я действительно не хочу использовать уродливый и нечитаемый вкладыш (нашел несколько таких в Интернете).Неужели нет прямого способа сделать это?

Ответы [ 6 ]

15 голосов
/ 02 ноября 2010

Список, который есть у вас в вашем примере, нельзя разрезать с конца.Это в основном потому, что списки - это не правильные структуры данных в Perl, а скорее конструкция, которую интерпретатор использует для перемещения данных.Поэтому, зная, что вы можете только нарезать список с самого начала, вы можете либо поместить его в переменную массива, а затем нарезать, изменить свой алгоритм, чтобы он возвращал то, что вы хотите, или следующее:

Если выприсвоив это значение чему-либо, вы можете использовать undef в каждом слоте, который вам не нужен:

 my (undef, @list) = split ' ' => $test_line;

Если вы добавите еще какой-то код, я могу изменить.

В качестве альтернативы, вы можете использоватьнекоторые инструменты из функционального программирования.Пара функций drop и take может быть полезна для изменения размера списка без дополнительных переменных:

sub take {
    my $n = shift;
    @_[0..$n-1]
}
sub drop {
    my $n = shift;
    @_[$n..$#_]
}

, и тогда ваш пример становится

drop 1, split ' ' => $test_line;

drop 1 такжеобычно называется tail

sub tail {drop 1, @_}

и, конечно, поскольку все они настолько короткие, если вы хотите вставить их в строку:

sub {shift; @_}->(split ' ' => ...)
6 голосов
/ 02 ноября 2010

Когда ОП сказал срез , я подумал о splice:

@allTheWordsExceptTheFirstTwo = splice @{[split' ', $test_line]}, 2;
@allExceptTheFirstAndLastTwo = splice @{[split' ', $test_line]}, 2, -2;
3 голосов
/ 02 ноября 2010

Вы можете использовать отрицательные диапазоны в индексе массива для адресации произвольного числа элементов с конца:

my $x = join ' ' => 'a' .. 'z';
my @x = (split ' ', $x)[-13 .. -1];

Однако для этого необходимо знать общее количество элементов в результате split чтобы исключить только первый элемент.

Если это происходит только в одном месте, использование блока do должно работать:

my $x = join ' ', 'a' .. 'z';
my @x = do { my @y = (split ' ', $x); @y[1 .. $#y] };

В вашем случае я бы выделил целоеОперация для подпрограммы, если предполагается, что она часто используется, передача строки, а не результата split в подпрограмму (может быть дополнительно обобщена путем предоставления пользователю возможности также передавать шаблон разбиения:

my $x = join ' ', 'a' .. 'g';
my @x = skip_first_n_from_split(3, $x);

print Dump \@x;

sub skip_first_n_from_split {
    my ($n, $x) = @_;
    my @y = split ' ', $x;
    return @y[$n .. $#y];
}

Веселились:

#!/usr/bin/perl

use strict; use warnings;

my $x = join ' ', 1 .. 8;
my @skippers = map make_skipper(' ', $_), 0 .. 7;

print "@$_\n" for map $_->($x), @skippers;

sub make_skipper {
    my ($pattern, $n) = @_;

    return sub {
        my $string = shift;
        my $i = 0;
        return [ grep $i++ >= $n, split $pattern, $string ];
    }
}

Вывод:

1 2 3 4 5 6 7 8
2 3 4 5 6 7 8
3 4 5 6 7 8
4 5 6 7 8
5 6 7 8
6 7 8
7 8
8
2 голосов
/ 27 ноября 2010

Это только что ответил 'аккуратно' на Perlmonks от BrowserUK, вот что вы бы сделали:

my @slice =  sub{ @_[1..$#_] }->( split ' ', $test_line );
2 голосов
/ 02 ноября 2010

Я не думаю, что вы можете указать индекс для последнего элемента произвольного выражения списка, но как насчет:

split(' ', (split ' ', $test_line, 2)[1])

Кстати, здесь нет анонимных массивов (или в вашемОригинальный вопрос), только списки.

0 голосов
/ 02 ноября 2010

, если вы открыты для разделения дважды:

my @g =  (split ' ', $test_str)[1..split(' ', $test_str)];

или более правильно (поскольку split возвращает количество найденных полей (на один больше, чем индекс последнего поля, поскольку оно основано на 0):

my @g =  (split ' ', $test_str)[1..split(' ', $test_str)-1];

к сожалению, они выбрасывают устаревшее предупреждение под прагмой 'warnings' и забивают содержимое @_ (если вы не используете 5.12, то все хорошо, в противном случае используйте временную переменную, встроенную подпрограмму или цикл).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...