9 votes

Impression de séries mathématiques de manière concise en Raku

Séries mathématiques, 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) };

Impressions :

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

a8 =  8
a9 =  9

1- Existe-t-il un moyen simple de ne déposer que le premier élément, c'est-à-dire a0 = 0 de la sortie imprimée ?

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

7voto

Vous pouvez ignorer les N premières valeurs sur tous Iterable o Sequence con skip :

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

Si vous ne spécifiez pas de nombre, un seul élément sera ignoré.

7voto

jjmerelo Points 173

Cela pourrait être un peu plus idiomatique :

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

Il n'est pas nécessaire d'utiliser une variable lexicale dans la séquence ; soit Whatever o variables de remplacement peuvent être utilisés en toute sécurité dans les séquences. Il vous suffit alors de sélectionner les éléments de la séquence que vous souhaitez imprimer. Qui renvoie «(0 1 2 3)(7 8 9 10)»

2voto

raiph Points 8552

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)
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X