В вашем входе четное количество элементов:
say elems <1 1 0 2 0 2 1 2 2 2 4 4 3 3>; # 14
Ваш grep
блок потребляет два элемента каждый раз:
{$^a eq $^b}
Поэтому, если вы добавите или удалите элемент, вы получите ошибку, которую вы получите, когда блок будет запущен для одного элемента, оставшегося в конце.
Есть много способов решить вашу проблему.
Но вы также спросили о возможности разрешения наложения, так что, например, вы получаете два (2 2)
подсписка, когда 2 2 2
встречается последовательность . И в аналогичном ключе вы, вероятно, хотите видеть два совпадения, а не ноль, с такими входными данными:
<1 2 2 3 3 4>
Поэтому я сосредоточусь на решениях, которые также касаются этих проблем.
Несмотря на сужение пространства решений для решения дополнительных проблем, есть еще много способов выразить решения функционально.
Один способ, который просто добавляет немного кода в конец вашего:
my @s = <1 1 0 2 0 2 1 2 2 2 4 4 3 3>;
say grep {$^a eq $^b}, @s .rotor( 2 => -1 ) .flat
.rotor
Метод преобразует список в список подсписков, каждый из одной и той же длины. Например, say <1 2 3 4> .rotor: 2
отображает ((1 2) (3 4))
. Если аргумент длины является парой, то ключ является длиной, а значение является смещением для начала следующей пары. Если смещение отрицательное, вы получаете перекрытие подсписка. Таким образом say <1 2 3 4> .rotor: 2 => -1
отображает ((1 2) (2 3) (3 4))
.
В .flat
методе «» его более плоский invocant. Например, say ((1,2),(2,3),(3,4)) .flat
отображает (1 2 2 3 3 4)
.
Возможно, более читаемый способ написания вышеприведенного решения состоит в том, чтобы опустить flat
и использовать .[0]
и .[1]
индексировать в подсписки, возвращаемые rotor
:
say @s .rotor( 2 => -1 ) .grep: { .[0] eq .[1] }
Смотрите также комментарий Элизабет Маттийсен для другого варианта, который обобщает для любого размера подсписка.
Если вам нужен более общий шаблон кодирования, вы можете написать что-то вроде:
say @s .pairs .map: { .value xx 2 if .key < @s - 1 and [eq] @s[.key,.key+1] }
.pairs
Метод в списке возвращает список пара, каждую пару , соответствующую каждый из элементов в его invocant списка. Значение .key
каждой пары - это индекс элемента в списке инвокантов; .value
является значением элемента.
.value xx 2
мог быть написан .value, .value
. (См xx
.)
@s - 1
количество элементов в @s
минус 1.
[eq]
В [eq] list
это сокращение .
Если вам нужно сопоставление с текстовым шаблоном, чтобы решить, из чего состоят смежные равные элементы, вы можете преобразовать входной список в строку, сопоставьте ее с помощью одного из наречий совпадений, которые генерируют список совпадений, а затем сопоставьте полученный итоговый список совпадений с вашим желаемым результат. Чтобы соответствовать с перекрытиями (например, 2 2 2
результаты в ((2 2) (2 2))
использовании :ov
:
say @s .Str .match( / (.) ' ' $0 /, :ov ) .map: { .[0].Str xx 2 }
2 2 2 2
она печатает 3(2 2)
с, как и ожидалось. Никогда не слышал о методе,rotor
я изначально придумал этотsquish
метод и проверил, есть ли у него такие особенности или аргументы, как у него,@s.squish(:length 2, :multiple_instances yes)
но у него не было таких функций, и он не подходит для этой задачи. По сравнению сsquish
,rotor
кажется, вполне подходит. На самом деле это может быть даже самый подходящий для этого типа операции.my $size = 2; say <1 1 0 2 0 2 1 2 2 2 4 4 3 3>.rotor( $size => -$size + 1).grep: { [eq] $_ }
# ((1 1) (2 2) (2 2) (4 4) (3 3)) Вам нужно только отрегулировать$size
для разных длин последовательностей.rotor
которые я добавил, ослабили или усилили мой ответ.rotor
решения, т.say @s.rotor(2=>-1).grep:{.[0]eq.[1]}
Е. Приветствуется, потому что она и короче (на 3–5 символов в зависимости от того, как подсчитаны пробелы) и все еще выглядит прилично. Такжеrotor
приветствуются обобщенные версии без метода, потому что они показывают, как используются некоторые причуды, подобныеxx
и:ov
. Так что проблема очень хорошо решена :)TIMTOWDI!
Вот итерационный подход с использованием
gather
/take
.источник
take ($last, $_)
Часть представляет собой достойный пример на использование этогоgather and take
дуэта.