Так вот, за последние полчаса меня заставляют заводить бонкеров. Есть ли способ для меня захватить срез массива до конца анонимного массива? Я пробовал: (split(' ',$test_line))[1..$#_]
и я пробовал:
(split(' ',$test_line))[1..-1]
но отягчающе, ни одна из них не работает. Я действительно не хочу иметь дополнительную временную переменную, созданную промежуточным массивом (мне это не нужно). И я действительно не хочу использовать уродливый и нечитаемый один лайнер (нашел несколько из них в Интернете). Неужели нет прямого способа сделать это?
Есть ли способ захватить фрагмент до конца анонимного массива в Perl?
Ответ 1
Список, который у вас есть в вашем примере, не может быть разрезан с конца. Это связано главным образом с тем, что списки не являются надлежащими структурами данных в 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 ' ' => ...)
Ответ 2
Когда OP сказал slice, я подумал о splice
:
@allTheWordsExceptTheFirstTwo = splice @{[split' ', $test_line]}, 2;
@allExceptTheFirstAndLastTwo = splice @{[split' ', $test_line]}, 2, -2;
Ответ 3
Вы можете использовать отрицательные диапазоны в индексе массива для обращения к произвольному количеству элементов с конца:
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
Ответ 4
Я не верю, что вы можете указать индекс для последнего элемента произвольного выражения списка, но как насчет:
split(' ', (split ' ', $test_line, 2)[1])
Кстати, анонимных массивов здесь нет (или в вашем исходном вопросе), только списки.
Ответ 5
Это только что ответили "аккуратно" на Perlmonks от BrowserUK, вот что вы сделали бы:
my @slice = sub{ @_[1..$#_] }->( split ' ', $test_line );
Ответ 6
если вы открыты для разделения дважды:
my @g = (split ' ', $test_str)[1..split(' ', $test_str)];
или более правильно (поскольку split возвращает количество найденных полей (на один больше, чем последний индекс поля, поскольку он основан на 0):
my @g = (split ' ', $test_str)[1..split(' ', $test_str)-1];
к сожалению, они вызывают устаревшее предупреждение под прагмой "предупреждения" и сжимают содержимое @_ (если вы не используете 5.12, тогда вы хороши, в противном случае используйте временную переменную, встроенную подпитку или цикл).