Ci sono un numero pari di elementi nel tuo input:
say elems <1 1 0 2 0 2 1 2 2 2 4 4 3 3>; # 14
Il tuo grep
blocco consuma due elementi ogni volta:
{$^a eq $^b}
Quindi se aggiungi o rimuovi un elemento otterrai l'errore che otterrai quando il blocco viene eseguito sul singolo elemento rimasto alla fine.
Esistono molti modi per risolvere il tuo problema.
Ma hai anche chiesto l'opzione di consentire la sovrapposizione, quindi, ad esempio, ottieni due (2 2)
elenchi secondari quando 2 2 2
si incontra la sequenza . E, in modo simile, presumibilmente vuoi vedere due corrispondenze, non zero, con input come:
<1 2 2 3 3 4>
Quindi mi concentrerò su soluzioni che affrontano anche questi problemi.
Nonostante il restringimento dello spazio della soluzione per affrontare i problemi aggiuntivi, ci sono ancora molti modi per esprimere le soluzioni in modo funzionale.
Un modo per aggiungere un po 'più di codice alla fine del tuo:
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
Il .rotor
metodo converte un elenco in un elenco di elenchi secondari, ciascuno della stessa lunghezza. Ad esempio, say <1 2 3 4> .rotor: 2
visualizza ((1 2) (3 4))
. Se l'argomento lunghezza è una coppia, la chiave è la lunghezza e il valore è un offset per l'avvio della coppia successiva. Se l'offset è negativo si ottiene la sovrapposizione dell'elenco secondario. Quindi say <1 2 3 4> .rotor: 2 => -1
visualizza ((1 2) (2 3) (3 4))
.
Il .flat
metodo "appiattisce" il suo invocante. Ad esempio, say ((1,2),(2,3),(3,4)) .flat
visualizza (1 2 2 3 3 4)
.
Un modo forse più leggibile per scrivere la soluzione di cui sopra sarebbe omettere flat
e utilizzare .[0]
e .[1]
indicizzare negli elenchi secondari restituiti da rotor
:
say @s .rotor( 2 => -1 ) .grep: { .[0] eq .[1] }
Vedi anche il commento di Elizabeth Mattijsen per un'altra variante che si generalizza per qualsiasi dimensione dell'elenco secondario.
Se ti servisse un modello di codifica più generale, potresti scrivere qualcosa del tipo:
say @s .pairs .map: { .value xx 2 if .key < @s - 1 and [eq] @s[.key,.key+1] }
Il .pairs
metodo in un elenco restituisce un elenco di coppie, ciascuna coppia corrispondente a ciascuno degli elementi nel suo elenco di invocanti. Il .key
di ciascuna coppia è l'indice dell'elemento nell'elenco di invocanti; la .value
è il valore dell'elemento.
.value xx 2
avrebbe potuto essere scritto .value, .value
. (Vedi xx
.)
@s - 1
è il numero di elementi in @s
meno 1.
L' [eq]
ingresso [eq] list
è una riduzione .
Se hai bisogno di una corrispondenza del modello di testo per decidere cosa costituisce elementi uguali contigui, potresti convertire l'elenco di input in una stringa, confrontalo con quello usando uno degli avverbi di corrispondenza che generano un elenco di corrispondenze, quindi mappa dall'elenco di corrispondenze risultante al desiderato risultato. Da abbinare a sovrapposizioni (ad es. 2 2 2
Risultati in ((2 2) (2 2))
uso :ov
:
say @s .Str .match( / (.) ' ' $0 /, :ov ) .map: { .[0].Str xx 2 }
2 2 2 2
, stampa 3(2 2)
s che è come previsto. Nonrotor
ho mai sentito parlare del metodo Inizialmente ho escogitato ilsquish
metodo e verificato se ha caratteristiche o argomenti come@s.squish(:length 2, :multiple_instances yes)
ma non aveva tali caratteristiche e non era adatto per l'attività. Rispetto alsquish
,rotor
sembra abbastanza in forma. In realtà potrebbe anche essere il più adatto per questo tipo di operazione.