Una soluzione barebone
Cominciamo con una soluzione molto semplice per stampare una sintesi di una sequenza. Non si occupa delle specifiche che hai aggiunto alla tua domanda, ma è un buon punto di partenza:
sub seq-range-gist ( @seq ) {
my @pairs = @seq.pairs;
join "\n", @pairs.head(3)».gist, '...', @pairs.tail(2)».gist
}
Diversamente .kv
, che converte il suo invocante nella forma key1, value1, key2, value2, key3, value3, ...
, ovvero 6 elementi se il suo invocante contiene 3 elementi, .pairs
converte il suo invocante nella forma key1 => value1, key2 => value2, key3 => value3, ...
.
Ho usato .pairs
invece in .kv
parte perché significava che avrei potuto usare ».gist
più avanti nel codice per ottenere facilmente una bella key1 => value1
visualizzazione per ogni elemento. Lo modificheremo di seguito, ma questo è un buon inizio idiomatico.
Le chiamate .head
e .tail
sono il modo idiomatico di creare piccoli elenchi del primo e dell'ultimo N elementi da un elenco invocante (purché non sia pigro; ne parleremo più in un attimo).
Data questa soluzione iniziale, say seq-range-gist (0,1 ... Inf)[^10]
visualizza:
0 => 0
1 => 1
2 => 2
...
8 => 8
9 => 9
Successivamente, vogliamo essere in grado di "eliminare solo il primo elemento ... dall'output stampato". Sfortunatamente say seq-range-gist (0,1 ... Inf)[1..9]
visualizza:
0 => 1
1 => 2
2 => 3
...
7 => 8
8 => 9
Vogliamo che il numero a sinistra di =>
mantenga la numerazione della sequenza originale. Per abilitare ciò abbiamo diviso la sequenza sottostante dall'intervallo che vogliamo estrarre. Aggiungiamo un secondo parametro / argomento @range
e aggiungiamo [@range]
alla seconda riga del sottotitolo:
sub seq-range-gist ( @seq, @range ) {
my @pairs = @seq.pairs[@range];
Ora possiamo scrivere say seq-range-gist (0,1 ... Inf), 1..9
per visualizzare:
1 => 1
2 => 2
3 => 3
...
8 => 8
9 => 9
Nella tua domanda hai utilizzato il formato aINDEX = VALUE
anziché INDEX => VALUE
. Per consentire la personalizzazione dell'essenza, aggiungiamo un terzo &gist
parametro / argomento di routine e lo invochiamo invece del .gist
metodo incorporato :
sub seq-range-gist ( @seq, @range, :&gist ) {
my @pairs = @seq.pairs[@range];
join "\n", @pairs.head(3)».&gist, '...', @pairs.tail(2)».&gist
}
Si noti come le invocazioni "metodo" nel corpo del seq-range-gist
sub sono ora .&gist
, non è .gist
. La sintassi .&foo
invoca un sub &foo
(che in genere viene invocato scrivendo semplicemente foo
), passando l'invocante a sinistra di .
come $_
argomento al sub.
Nota anche che ho reso il &gist
parametro un nome precedendolo con a :
.
Quindi ora say seq-range-gist (0,1 ... Inf), 1..9, gist => { "a{.key} = {.value}" }
visualizza:
a1 = 1
a2 = 2
a3 = 3
...
a8 = 8
a9 = 9
Aggiunta di smalto
Il resto di questa risposta è materiale bonus per i lettori che si preoccupano della lucidatura.
say seq-range-gist (0, 1, 2, 3), ^3
display:
0 => 0
1 => 1
2 => 2
...
1 => 1
2 => 2
Ops. E anche se ci fossero più coppie della testa e della coda combinate, quindi almeno non abbiamo ottenuto linee ripetute, sarebbe comunque inutile usare l' head, ..., tail
approccio per eludere solo uno o due elementi. Modifichiamo l'ultima istruzione nel corpo secondario per eliminare questi problemi:
join "\n",
@pairs < $head + $tail + 3 # Of course, the 3 is a bit arbitrary
?? @pairs».&gist
!! (@pairs.head($head)».&gist, '...', @pairs.tail($tail)».&gist)
Successivamente, sarebbe bello se il sub facesse qualcosa di utile se chiamato senza intervallo o sostanza. Possiamo principalmente risolverlo fornendo i parametri @range
e &gist
i valori predefiniti adeguati:
sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:&gist = { .gist }
) {
Se non@seq
è pigro , il valore predefinito è l'intero . Se è infinito (nel qual caso è anche pigro), allora il valore predefinito fino a 100 va bene. Ma cosa succede se è pigro ma produce meno di 100 valori definiti? Per coprire questo caso aggiungiamo alla dichiarazione: @range
@seq
@seq
@seq
.grep: *.value.defined
@pairs
my @pairs = @seq.pairs[@range].grep: *.value.defined;
Un altro semplice miglioramento sarebbero i parametri opzionali di testa e coda, che porterebbero a una soluzione finale raffinata:
sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:$head = 3,
:$tail = 2,
:&gist = { .gist }
) {
my @pairs = @seq.pairs[@range].grep: *.value.defined;
join "\n",
@pairs <= $head + $tail + 2
?? @pairs».&gist
!! (@pairs.head($head)».&gist, '...', @pairs.tail($tail)».&gist)
}