Há um número par de elementos em sua entrada:
say elems <1 1 0 2 0 2 1 2 2 2 4 4 3 3>; # 14
Seu grep
bloco consome dois elementos de cada vez:
{$^a eq $^b}
Portanto, se você adicionar ou remover um elemento, receberá o erro que ocorrerá quando o bloco for executado no único elemento restante no final.
Existem muitas maneiras de resolver seu problema.
Mas você também perguntou sobre a opção de permitir sobreposição, por exemplo, você recebe duas (2 2)
sub-listas quando a sequência 2 2 2
é encontrada. E, de maneira semelhante, você presumivelmente deseja ver duas correspondências, não zero, com entradas como:
<1 2 2 3 3 4>
Então, vou me concentrar em soluções que lidam com esses problemas também.
Apesar do estreitamento do espaço da solução para lidar com os problemas extras, ainda existem muitas maneiras de expressar soluções funcionalmente.
Uma maneira de adicionar um pouco mais de código ao final do seu:
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
O .rotor
método converte uma lista em uma lista de sub-listas, cada uma com o mesmo comprimento. Por exemplo, é say <1 2 3 4> .rotor: 2
exibido ((1 2) (3 4))
. Se o argumento do comprimento for um par, a chave será o comprimento e o valor será um deslocamento para iniciar o próximo par. Se o deslocamento for negativo, você terá sobreposição da sub-lista. Assim é say <1 2 3 4> .rotor: 2 => -1
exibido ((1 2) (2 3) (3 4))
.
O .flat
método "nivela" seu invocante. Por exemplo, é say ((1,2),(2,3),(3,4)) .flat
exibido (1 2 2 3 3 4)
.
Uma maneira talvez mais legível de escrever a solução acima seria omitir flat
e usar .[0]
e .[1]
indexar nas sub-listas retornadas por rotor
:
say @s .rotor( 2 => -1 ) .grep: { .[0] eq .[1] }
Veja também o comentário de Elizabeth Mattijsen para outra variação generalizada para qualquer tamanho de sub-lista.
Se você precisava de um padrão de codificação mais geral, escreva algo como:
say @s .pairs .map: { .value xx 2 if .key < @s - 1 and [eq] @s[.key,.key+1] }
O .pairs
método em uma lista retorna uma lista de pares, cada par correspondendo a cada um dos elementos em sua lista invocante. O .key
de cada par é o índice do elemento na lista invocante; o .value
é o valor do elemento.
.value xx 2
poderia ter sido escrito .value, .value
. (Veja xx
.)
@s - 1
é o número de elementos em @s
menos 1.
A [eq]
na [eq] list
é uma redução .
Se você precisar de correspondência de padrão de texto para decidir o que constitui elementos iguais contíguos, poderá converter a lista de entrada em uma sequência, faça a correspondência com essa usando um dos advérbios de correspondência que geram uma lista de correspondências e mapeie a partir da lista de correspondências resultante para a desejada resultado. Para combinar com sobreposições (por exemplo, 2 2 2
resultados em ((2 2) (2 2))
uso :ov
:
say @s .Str .match( / (.) ' ' $0 /, :ov ) .map: { .[0].Str xx 2 }
2 2 2 2
ele imprime 3(2 2)
s, conforme o esperado. Nunca ouvi falar do métodorotor
. Inicialmente, inventei osquish
método e verifiquei se ele possui características ou argumentos semelhantes,@s.squish(:length 2, :multiple_instances yes)
mas não possuía essas características e não era adequado para a tarefa. Comparado com osquish
,rotor
parece bastante adequado. Na verdade, pode até ser o mais adequado para esse tipo de operação.