Il y a un nombre pair d'éléments dans votre entrée:
say elems <1 1 0 2 0 2 1 2 2 2 4 4 3 3>; # 14
Votre grep
bloc consomme à chaque fois deux éléments:
{$^a eq $^b}
Donc, si vous ajoutez ou supprimez un élément, vous obtiendrez l'erreur que vous obtenez lorsque le bloc est exécuté sur le seul élément restant à la fin.
Il existe de nombreuses façons de résoudre votre problème.
Mais vous avez également demandé l'option de permettre le chevauchement, par exemple, vous obtenez deux (2 2)
sous-listes lorsque la séquence 2 2 2
est rencontrée. Et, dans la même veine, vous voulez probablement voir deux correspondances, pas zéro, avec une entrée comme:
<1 2 2 3 3 4>
Je vais donc me concentrer sur les solutions qui traitent également de ces problèmes.
Malgré le rétrécissement de l'espace des solutions pour traiter les problèmes supplémentaires, il existe encore de nombreuses façons d'exprimer les solutions de manière fonctionnelle.
Une façon qui ajoute juste un peu plus de code à la fin de la vôtre:
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
La .rotor
méthode convertit une liste en une liste de sous-listes, chacune de la même longueur. Par exemple, say <1 2 3 4> .rotor: 2
s'affiche ((1 2) (3 4))
. Si l'argument de longueur est une paire, la clé est la longueur et la valeur est un décalage pour démarrer la paire suivante. Si le décalage est négatif, vous obtenez un chevauchement de sous-liste. say <1 2 3 4> .rotor: 2 => -1
Affiche ainsi ((1 2) (2 3) (3 4))
.
La .flat
méthode "aplatit" son invocant. Par exemple, say ((1,2),(2,3),(3,4)) .flat
s'affiche (1 2 2 3 3 4)
.
Une façon peut-être plus lisible d'écrire la solution ci-dessus serait d'omettre flat
et d'utiliser .[0]
et .[1]
d'indexer dans les sous-listes renvoyées par rotor
:
say @s .rotor( 2 => -1 ) .grep: { .[0] eq .[1] }
Voir aussi le commentaire d'Elizabeth Mattijsen pour une autre variation qui se généralise pour toute taille de sous-liste.
Si vous aviez besoin d'un modèle de codage plus général, vous pourriez écrire quelque chose comme:
say @s .pairs .map: { .value xx 2 if .key < @s - 1 and [eq] @s[.key,.key+1] }
La .pairs
méthode sur une liste renvoie une liste de paires, chaque paire correspondant à chacun des éléments de sa liste invocante. Le .key
de chaque paire est l'indice de l'élément dans la liste invocante; l' .value
est la valeur de l'élément.
.value xx 2
aurait pu être écrit .value, .value
. (Voir xx
.)
@s - 1
est le nombre d'éléments en @s
moins 1.
L' [eq]
entrée [eq] list
est une réduction .
Si vous avez besoin d'une correspondance de modèle de texte pour décider de ce qui constitue des éléments égaux contigus, vous pouvez convertir la liste d'entrée en chaîne, comparez-la à celle-ci en utilisant l'un des adverbes de correspondance qui génèrent une liste de correspondances, puis mappez la liste de correspondances résultante vers la liste souhaitée résultat. Pour correspondre aux chevauchements (par exemple, les 2 2 2
résultats d' ((2 2) (2 2))
utilisation :ov
:
say @s .Str .match( / (.) ' ' $0 /, :ov ) .map: { .[0].Str xx 2 }
2 2 2 2
il imprime 3(2 2)
s, ce qui est comme prévu.rotor
Je n'ai jamais entendu parler de la méthode.J'ai initialement proposé cettesquish
méthode et vérifié si elle avait des fonctionnalités ou des arguments comme,@s.squish(:length 2, :multiple_instances yes)
mais elle n'en avait pas et elle n'était pas adaptée à la tâche. Par rapport ausquish
,rotor
semble tout à fait en forme. En fait, il pourrait même être le plus adapté à ce type d'opération.