Una solución básica
Comencemos con una solución muy simple para imprimir la esencia de una secuencia. No trata los detalles que ha agregado a su pregunta, pero es un buen punto de partida:
sub seq-range-gist ( @seq ) {
my @pairs = @seq.pairs;
join "\n", @pairs.head(3)».gist, '...', @pairs.tail(2)».gist
}
A diferencia .kv
, lo que convierte su invocante en la forma key1, value1, key2, value2, key3, value3, ...
, es decir, 6 elementos si su invocante contiene 3 elementos, .pairs
convierte su invocante en la forma key1 => value1, key2 => value2, key3 => value3, ...
.
Lo usé en .pairs
lugar de en .kv
parte porque significaba que podría usarlo ».gist
más adelante en el código para obtener sin esfuerzo una buena key1 => value1
visualización de cada elemento. Lo modificaremos a continuación, pero este es un buen comienzo idiomático.
Las llamadas .head
y .tail
son la forma idiomática de crear pequeñas listas de los primeros y últimos N elementos de una lista de invocadores (siempre que no sea vago; más sobre eso en un momento).
Dada esta solución inicial, say seq-range-gist (0,1 ... Inf)[^10]
muestra:
0 => 0
1 => 1
2 => 2
...
8 => 8
9 => 9
A continuación, queremos poder "soltar solo el primer elemento ... de la salida impresa". Desafortunadamente say seq-range-gist (0,1 ... Inf)[1..9]
muestra:
0 => 1
1 => 2
2 => 3
...
7 => 8
8 => 9
Queremos que el número a la izquierda del =>
retenga la numeración de la secuencia original. Para habilitar esto, dividimos la secuencia subyacente del rango que queremos extraer. Agregamos un segundo parámetro / argumento @range
, y agregamos [@range]
a la segunda línea del sub:
sub seq-range-gist ( @seq, @range ) {
my @pairs = @seq.pairs[@range];
Ahora podemos escribir say seq-range-gist (0,1 ... Inf), 1..9
para mostrar:
1 => 1
2 => 2
3 => 3
...
8 => 8
9 => 9
En su pregunta, utilizó el formato en aINDEX = VALUE
lugar de INDEX => VALUE
. Para permitir la personalización de la esencia, agregamos un tercer &gist
parámetro / argumento de rutina e invocamos eso en lugar del .gist
método incorporado :
sub seq-range-gist ( @seq, @range, :&gist ) {
my @pairs = @seq.pairs[@range];
join "\n", @pairs.head(3)».&gist, '...', @pairs.tail(2)».&gist
}
Observe cómo las invocaciones de "método" en el cuerpo de seq-range-gist
sub son ahora .&gist
, no .gist
. La sintaxis .&foo
invoca un sub &foo
(que generalmente se invoca escribiendo solo foo
), pasando el invocante a la izquierda del .
como un $_
argumento para el sub.
Tenga en cuenta también que he hecho que el &gist
parámetro tenga un nombre precediéndolo con un :
.
Entonces ahora say seq-range-gist (0,1 ... Inf), 1..9, gist => { "a{.key} = {.value}" }
muestra:
a1 = 1
a2 = 2
a3 = 3
...
a8 = 8
a9 = 9
Agregar esmalte
El resto de esta respuesta es material adicional para los lectores que se preocupan por el esmalte.
say seq-range-gist (0, 1, 2, 3), ^3
muestra:
0 => 0
1 => 1
2 => 2
...
1 => 1
2 => 2
Ups E incluso si hubiera más pares que la cabeza y la cola combinados, por lo que al menos no obtuvimos líneas repetidas, aún sería inútil usar el head, ..., tail
enfoque para eludir solo uno o dos elementos. Cambiemos la última declaración en el sub cuerpo para eliminar estos problemas:
join "\n",
@pairs < $head + $tail + 3 # Of course, the 3 is a bit arbitrary
?? @pairs».&gist
!! (@pairs.head($head)».&gist, '...', @pairs.tail($tail)».&gist)
A continuación, sería bueno que el submarino hiciera algo útil si se llama sin un rango o esencia. Sobre todo que podemos arreglar que al dar a las @range
y &gist
los parámetros por defecto adecuados:
sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:&gist = { .gist }
) {
Si no@seq
es perezoso , el valor predeterminado es el rango completo de . Si es infinito (en cuyo caso también es vago), entonces el valor predeterminado de hasta 100 está bien. Pero, ¿qué pasa si es perezoso pero produce menos de 100 valores definidos? Para cubrir este caso, adjuntamos a la declaración: @range
@seq
@seq
@seq
.grep: *.value.defined
@pairs
my @pairs = @seq.pairs[@range].grep: *.value.defined;
Otra mejora simple serían los parámetros opcionales de cabeza y cola, lo que llevaría a una solución final pulida:
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)
}