Une solution barebones
Commençons par une solution très simple pour imprimer l'essentiel d'une séquence. Il ne traite pas des détails que vous avez ajoutés à votre question, mais c'est un bon point de départ:
sub seq-range-gist ( @seq ) {
my @pairs = @seq.pairs;
join "\n", @pairs.head(3)».gist, '...', @pairs.tail(2)».gist
}
Contrairement .kv
, qui convertit son invocant en forme key1, value1, key2, value2, key3, value3, ...
, c'est-à-dire 6 éléments si son invocant contient 3 éléments, .pairs
convertit son invocant en forme key1 => value1, key2 => value2, key3 => value3, ...
.
J'ai utilisé .pairs
au lieu de .kv
partiellement parce que cela signifiait que je pouvais simplement utiliser ».gist
plus tard dans le code pour obtenir sans effort un bel key1 => value1
affichage pour chaque élément. Nous allons modifier cela ci-dessous mais c'est un bon début idiomatique.
Le .head
et.tail
appels sont le moyen idiomatique de créer de petites listes des premier et dernier N éléments à partir d'une liste invocante (à condition que ce ne soit pas paresseux; plus à ce sujet dans un mois).
Compte tenu de cette solution initiale, say seq-range-gist (0,1 ... Inf)[^10]
affiche:
0 => 0
1 => 1
2 => 2
...
8 => 8
9 => 9
Ensuite, nous voulons pouvoir "supprimer uniquement le premier élément ... de la sortie imprimée". say seq-range-gist (0,1 ... Inf)[1..9]
Affiche malheureusement :
0 => 1
1 => 2
2 => 3
...
7 => 8
8 => 9
Nous voulons que le numéro à gauche de la =>
conserve la numérotation de la séquence d'origine. Pour activer cela, nous séparons la séquence sous-jacente de la plage que nous voulons extraire. Nous ajoutons un deuxième paramètre / argument @range
, et ajoutons [@range]
à la deuxième ligne du sous:
sub seq-range-gist ( @seq, @range ) {
my @pairs = @seq.pairs[@range];
Maintenant, nous pouvons écrire say seq-range-gist (0,1 ... Inf), 1..9
pour afficher:
1 => 1
2 => 2
3 => 3
...
8 => 8
9 => 9
Dans votre question, vous avez utilisé le format aINDEX = VALUE
plutôt que INDEX => VALUE
. Pour permettre la personnalisation de l'essentiel, nous ajoutons un troisième &gist
paramètre / argument de routine et l'invoquons à la place de la .gist
méthode intégrée :
sub seq-range-gist ( @seq, @range, :&gist ) {
my @pairs = @seq.pairs[@range];
join "\n", @pairs.head(3)».&gist, '...', @pairs.tail(2)».&gist
}
Notez comment les invocations de "méthode" dans le corps de seq-range-gist
sub ne sont .&gist
plus .gist
. La syntaxe .&foo
invoque un sous - marin&foo
(qui est généralement appelé en écrivant simplement foo
), en passant l'invocant à gauche de l' argument .
comme $_
argument au sous-marin.
Notez également que j'ai rendu le &gist
paramètre nommé en le précédant d'un :
.
say seq-range-gist (0,1 ... Inf), 1..9, gist => { "a{.key} = {.value}" }
Affiche maintenant :
a1 = 1
a2 = 2
a3 = 3
...
a8 = 8
a9 = 9
Ajout de vernis
Le reste de cette réponse est du matériel bonus pour les lecteurs qui se soucient du polonais.
say seq-range-gist (0, 1, 2, 3), ^3
affiche:
0 => 0
1 => 1
2 => 2
...
1 => 1
2 => 2
Oops. Et même s'il y avait plus de paires que la tête et la queue combinées, donc au moins nous n'avions pas de lignes répétées, il serait toujours inutile d'utiliser l' head, ..., tail
approche pour élider un ou deux éléments. Modifions la dernière instruction du sous-corps pour éliminer ces problèmes:
join "\n",
@pairs < $head + $tail + 3 # Of course, the 3 is a bit arbitrary
?? @pairs».&gist
!! (@pairs.head($head)».&gist, '...', @pairs.tail($tail)».&gist)
Ensuite, ce serait bien si le sous-marin faisait quelque chose d'utile s'il était appelé sans plage ni contenu. Nous pouvons principalement résoudre ce problème en donnant aux paramètres @range
et &gist
les valeurs par défaut appropriées:
sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:&gist = { .gist }
) {
Si @seq
n'est pas paresseux , par @range
défaut, la plage complète de @seq
. Si @seq
est infini (auquel cas il est également paresseux), la valeur par défaut jusqu'à 100 est correcte. Mais que faire si @seq
est paresseux mais donne moins de 100 valeurs définies? Pour couvrir ce cas, nous annexons .grep: *.value.defined
à la @pairs
déclaration:
my @pairs = @seq.pairs[@range].grep: *.value.defined;
Une autre amélioration simple serait les paramètres facultatifs de tête et de queue, conduisant à une solution finale polie:
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)
}