Perl идиома для получения максимального количества элементов в массиве - PullRequest
6 голосов
/ 27 июля 2010

Я хотел отрубить все, кроме первых пяти элементов массива, поэтому я тупо сделал:

@foo = @foo[ 0 .. 4 ];

и от всей души похвалил мою собственную хитрость.Но это сломалось, как только @foo закончилось только с тремя элементами, потому что тогда я закончил с двумя undef с конца вместо трехэлементного массива.Поэтому я изменил его на:

@foo = @foo > 5 ? @foo[ 0 .. 4 ] : @foo;

Это работает, но довольно уродливо.Есть ли лучшая идиома для выражения «дайте мне все до первых пяти элементов массива?»

Ответы [ 4 ]

8 голосов
/ 28 июля 2010

Вы можете установить последний индекс массива для его сокращения или удлинения. Как и ваш код, вам нужно проверить, чтобы убедиться, что вы не создаете undef-элементы.

$#foo = 4 if $#foo > 4;
6 голосов
/ 28 июля 2010

Еще один способ:

@foo = splice(@foo, 0, 5);

В отличие от других предложений по сращиванию, это не вызывает предупреждение; 5 явно означает «до 5».

6 голосов
/ 27 июля 2010

Если вас не волнуют мутации (подразумеваемые самореферентными lhs @foo = что-то, ссылающиеся на @foo), используйте два аргумента splice(), см. perldoc - f сращивание для получения дополнительной информации.

Сращивать массив, смещение

Удаляет элементы, обозначенные OFFSET и LENGTH, из массива и заменяет их элементами LIST, если таковые имеются. В контексте списка возвращает элементы, удаленные из массива , В скалярном контексте возвращает последний удаленный элемент или «undef», если элементы не удалены. Массив увеличивается или уменьшается по мере необходимости. Если OFFSET отрицателен, то он начинается так далеко от конца массива. Если ДЛИНА опущена, удаляет все с OFFSET и далее. Если LENGTH отрицателен, удаляет элементы из OFFSET и далее, за исключением элементов -LENGTH в конце массива. Если оба параметра OFFSET и LENGTH опущены, удаляется все. Если OFFSET находится за концом массива, perl выдает предупреждение и склеивает в конце массива.

Затем следите за эффектом:

@_ = 1..10;
splice @_, 5;
say for @_;


@_ = 1..3;
splice @_, 5;
say for @_;

Если вы используете warnings, и я надеюсь, что вам придется проверить длину (как в предложении Аксемана) или отключить шумовое предупреждение ( splice () смещено за конец массива ):

{
  no warnings 'misc';
  splice @_, 5;
}
1 голос
/ 27 июля 2010

Это не так изящно, но вы можете выразить это так:

@foo[ 0..( $#foo > 4 ? 4 : $#foo ) ];

Обобщенная функция min может выглядеть лучше.

use List::Util qw<min>;    
@foo[ 0..min( $#foo, 4 ) ];

Но если вы просто хотите избавиться от всего остального, вам просто нужно splice от всего остального:

splice( @foo, 5 ) if 5 < @foo;
...