Impression concise de séries mathématiques en Raku

9

Série mathématique, prenez par exemple la séquence consécutive représentée ici sous forme de tableau:

my @seq = my $a=0, {++$a} ... *;
for @seq[^10].kv {state $f=0; ($^k < 4 or $^k > 7) ?? say "a$^k =  "  ~ $^v !! (say "..." if $f ne 1; $f=1) };

Tirages:

a0 =  0
a1 =  1
a2 =  2
...

a8 =  8
a9 =  9

Mes questions: 1- Existe-t-il un moyen simple de supprimer uniquement le premier élément, c'est- a0 = 0à- dire de la sortie imprimée?

2- Ce code pourrait-il être rendu plus idiomatique?

Je vous remercie.

Lars Malmsteen
la source
@DanBron Merci pour le commentaire. Je viens d'éditer et de développer le post original.
Lars Malmsteen

Réponses:

2

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, .pairsconvertit son invocant en forme key1 => value1, key2 => value2, key3 => value3, ....

J'ai utilisé .pairsau lieu de .kvpartiellement parce que cela signifiait que je pouvais simplement utiliser ».gistplus tard dans le code pour obtenir sans effort un bel key1 => value1affichage pour chaque élément. Nous allons modifier cela ci-dessous mais c'est un bon début idiomatique.

Le .headet.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..9pour afficher:

1 => 1
2 => 2
3 => 3
...
8 => 8
9 => 9

Dans votre question, vous avez utilisé le format aINDEX = VALUEplutôt que INDEX => VALUE. Pour permettre la personnalisation de l'essentiel, nous ajoutons un troisième &gistparamètre / argument de routine et l'invoquons à la place de la .gistmé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-gistsub ne sont .&gistplus .gist. La syntaxe .&fooinvoque 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 &gistparamè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, ..., tailapproche 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 @rangeet &gistles valeurs par défaut appropriées:

sub seq-range-gist (
  @seq,
  @range = @seq.is-lazy ?? ^100 !! ^@seq,
  :&gist = { .gist }
) {

Si @seqn'est pas paresseux , par @rangedéfaut, la plage complète de @seq. Si @seqest infini (auquel cas il est également paresseux), la valeur par défaut jusqu'à 100 est correcte. Mais que faire si @seqest paresseux mais donne moins de 100 valeurs définies? Pour couvrir ce cas, nous annexons .grep: *.value.definedà la @pairsdé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)
}
raiph
la source
La solution minimale fonctionne très bien et elle est également décemment idiomatique. Dans ma solution, j'ai dû recourir à une variable 'flag' pour tenir compte de la ...partie qui la faisait ressembler davantage à un programme C. Donc, cela répond vraiment aux deux parties de ma question. Quant à la solution «globale», elle semble vraiment un peu intimidante.
Lars Malmsteen
Merci pour vos commentaires et pour avoir accepté ma réponse @LarsMalmsteen. Cela dit, j'ai entièrement réécrit ma réponse et je pense que c'est beaucoup mieux. J'ai abandonné la solution «globale» - j'étais allé loin dans les mauvaises herbes avec ça! - mais j'ai aussi complètement réécrit la "solution minimale" et l'explication qui l'accompagne. Je l'ai fait principalement pour d'autres lecteurs ultérieurs, mais vous pourriez tirer un avantage de la lecture de la nouvelle réponse.
raiph
7

Vous pouvez ignorer les N premières valeurs sur n'importe laquelle Iterable ou Sequenceavec skip:

for (^5).skip(3) {
    .say
}
# 3
# 4

Si vous ne spécifiez pas de nombre, il ne sautera qu'un seul élément.

Elizabeth Mattijsen
la source
Le skipsemble supprimer uniquement la sortie, c'est-à-dire que l'élément avec le 0ème indice (a0) reste. J'ai essayé @seq:deleteet il vient de remplacer le 0ème élément par(Any)
Lars Malmsteen
En effet. Le skipva simplement agir comme si les éléments ignorés n'existaient pas. Cela peut ou non être ce que vous voulez :-)
Elizabeth Mattijsen
Quand je mets l' skipentre entre deux pour qu'il se lise: for @seq[^10].skip(0).kvil ne saute littéralement pas le 0ème élément et peu importe si je donne comme argument à skip1 ou 2, cela déforme juste la sortie de plus. J'ai besoin d'un moyen pratique pour retirer le 0ème élément du sol.
Lars Malmsteen
1
C'est peut for @seq[^10].kv.skip(2)- être ce que vous cherchez?
Elizabeth Mattijsen
Oui, ça fait l'affaire. En fait, j'ai essayé de mettre l' skipafter, .kvmais en utilisant des arguments autres que 2, donc cela n'a pas fonctionné. Merci pour la solution.
Lars Malmsteen
7

Cela pourrait être un peu plus idiomatique:

my @seq = 0, *+1 ... *;
say @seq[^4], @seq[7..10]

Vous n'avez pas besoin d'utiliser une variable lexicale dans la séquence; l'une Whateverou l' autre des variables d'espace réservé peuvent être utilisées en toute sécurité dans les séquences. Ensuite, vous pouvez simplement sélectionner les éléments de la séquence que vous souhaitez imprimer. Qui revient«(0 1 2 3)(7 8 9 10)␤»

jjmerelo
la source
Merci pour la réponse. L' whateveropérateur rafraîchit mais la sortie série / séquence ne résout pas le problème principal. Je voudrais imprimer la série telle qu'elle apparaît sur les livres de mathématiques, c'est-à-dire avec une ...notation entre les deux.
Lars Malmsteen
@LarsMalmsteen, OK, je vais le modifier
jjmerelo