Une solution simple
Commençons par une solution très simple pour imprimer l'essentiel d'une séquence. Elle ne répond pas aux spécificités que vous avez ajoutées à 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 invocateur sous la forme key1, value1, key2, value2, key3, value3, ...
c'est-à-dire 6 éléments si son invocateur contient 3 éléments, .pairs
convertit son invocateur sous la forme key1 => value1, key2 => value2, key3 => value3, ...
.
J'ai utilisé .pairs
au lieu de .kv
en partie parce que cela signifiait que je pouvais simplement utiliser ».gist
plus loin dans le code pour obtenir sans effort une belle key1 => value1
pour chaque élément. Nous modifierons cela plus loin, mais il s'agit d'un bon point de départ idiomatique.
Le .head
et .tail
sont le moyen idiomatique de créer de petites listes de N premiers et derniers éléments à partir d'une liste invocante (à condition qu'elle ne soit pas paresseuse ; plus d'informations à ce sujet dans un mo).
Compte tenu de cette solution initiale, say seq-range-gist (0,1 ... Inf)[^10]
affichent :
0 => 0
1 => 1
2 => 2
...
8 => 8
9 => 9
Ensuite, nous voulons être en mesure de "supprimer uniquement le premier élément ... de la sortie imprimée". Malheureusement say seq-range-gist (0,1 ... Inf)[1..9]
affichent :
0 => 1
1 => 2
2 => 3
...
7 => 8
8 => 9
Nous voulons que le nombre à gauche du =>
pour conserver la numérotation de la séquence originale. Pour ce faire, 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 ajouter [@range]
à la deuxième ligne du sous-titre :
sub seq-range-gist ( @seq, @range ) {
my @pairs = @seq.pairs[@range];
Nous pouvons maintenant écrire say seq-range-gist (0,1 ... Inf), 1..9
pour l'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 la liste, nous ajoutons un troisième élément &gist
et l'invoquer à la place de la routine intégrée. .gist
méthode :
sub seq-range-gist ( @seq, @range, :&gist ) {
my @pairs = @seq.pairs[@range];
join "\n", @pairs.head(3)».&gist, '...', @pairs.tail(2)».&gist
}
Notez que les invocations de "méthodes" dans le corps de l'article seq-range-gist
sub sont maintenant .&gist
, pas .gist
. La syntaxe .&foo
invoque un sous &foo
(qui est généralement invoqué en écrivant simplement foo
), en passant l'invocateur à gauche de l'invocateur .
en tant que $_
à l'argument du sous-ensemble.
Notez également que j'ai rendu le &gist
un paramètre nommé en le faisant précéder d'un :
.
Alors maintenant say seq-range-gist (0,1 ... Inf), 1..9, gist => { "a{.key} = {.value}" }
affichent :
a1 = 1
a2 = 2
a3 = 3
...
a8 = 8
a9 = 9
Ajout de vernis
Le reste de cette réponse est un bonus pour les lecteurs qui s'intéressent au polissage.
say seq-range-gist (0, 1, 2, 3), ^3
affichent :
0 => 0
1 => 1
2 => 2
...
1 => 1
2 => 2
Oups ! Et même s'il y avait plus de paires que la tête et la queue combinées, de sorte qu'au moins nous n'obtenions pas de lignes répétées, il serait toujours inutile d'utiliser la fonction head, ..., tail
pour éluder un ou deux éléments seulement. Modifions la dernière déclaration dans le sous-corps afin d'é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, il serait bon que le sub fasse quelque chose d'utile s'il est appelé sans range ou gist. Nous pouvons en grande partie corriger cela en donnant à la fonction @range
et &gist
les paramètres par défaut appropriés :
sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:&gist = { .gist }
) {
Si @seq
es pas paresseux entonces @range
par défaut, l'éventail complet des @seq
. Si @seq
es infini (dans ce cas, il est également paresseux), alors la fonction jusqu'à 100 La valeur par défaut est correcte. Mais que se passe-t-il si @seq
est paresseux mais donne moins de 100 valeurs définies ? Pour couvrir ce cas, nous ajoutons .grep: *.value.defined
à la @pairs
déclaration :
my @pairs = @seq.pairs[@range].grep: *.value.defined;
Une autre amélioration simple consisterait à proposer des paramètres optionnels pour la tête et la queue, ce qui permettrait d'obtenir 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)
}