arrays - perl6 Quel est un moyen rapide de désélectionner des éléments de tableau ou de liste?




set deselect (3)

Étant donné que l'indexeur souhaite extraire les éléments, nous pourrions résoudre ce problème en transformant la liste des éléments à exclure en une liste de plages d'éléments à extraire. C'est, étant donné:

1, 3, 5

Nous produirions quelque chose d'équivalent à:

0..0, 2..2, 4..4, 6..Inf

Donné:

my @exclude = 1, 3, 5;

Nous pouvons faire:

-1, |@exclude Z^..^ |@exclude, Inf

Pour le décomposer, zip (-1, 1, 3, 5) avec (1, 3, 5, Inf) , mais en utilisant l'opérateur de plage avec des points de terminaison exclusifs. Cela donne, pour l'exemple donné:

(-1^..^1 1^..^3 3^..^5 5^..^Inf)

Ce qui est équivalent aux gammes que j'ai mentionnées ci-dessus. Ensuite, nous collons ceci dans l'indexeur:

my @a = <a b c d e f g>
my @exclude = 1, 3, 5;
say @a[-1, |@exclude Z^..^ |@exclude, Inf].flat

Ce qui donne le résultat souhaité:

(a c e g)

Cette approche est O (n + m). Cela fonctionnera probablement très bien si le tableau est long, mais le nombre d'éléments à exclure est comparativement faible, car il ne produit que les objets Range nécessaires à l'indexation, puis l'indexation par plage est relativement bien optimisée.

Enfin, si l’ flat extérieur est considéré comme gênant, il est également possible de le déplacer à l’intérieur:

@a[{ flat -1, |@exclude Z^..^ |@exclude, $_ }]

Ce qui fonctionne parce que le bloc reçoit le nombre d'éléments dans @a .

Pour sélectionner plusieurs éléments d'un tableau dans perl6, rien de plus simple: utilisez simplement une liste d'index:

> my @a = < a b c d e f g >;
> @a[ 1,3,5 ]
(b d f)

Mais pour désélectionner ces éléments, je devais utiliser Set:

> say @a[ (@a.keys.Set (-) (1,3,5)).keys.sort ]
(a c e g)

Je me demande s’il existe un moyen plus simple, car les tableaux que j’utilise sont souvent assez grands.


Cela peut être lent pour les grands tableaux, mais c'est logiquement le plus proche de ce que vous recherchez:

my @a = <a b c d>;

say (@a ⊖ @a[0,1]).keys; # (c d)

Il s'agit essentiellement de la même solution que celle que vous aviez proposée au début, en utilisant set difference, sauf que vous l'utilisez pour l'ensemble du tableau plutôt que pour les indices. De plus, dans certains cas, vous pouvez utiliser l’ensemble directement; cela dépend de ce que vous voulez faire.


sub infix:<not-at> ($elems, @not-ats) {
  my $at = 0;
  flat gather for @not-ats -> $not-at {
    when $at < $not-at { take $at++ xx $not-at - $at } 
    NEXT { $at++ }
    LAST { take $at++ xx $elems - $not-at - 1 }
  }
}

my @a = < a b c d e f g >;
say @a[ * not-at (1, 3, 5) ]; # (a c e g)

Je pense que le code opérateur est explicite, si vous connaissez chacune des constructions P6 qu’il utilise. Si quelqu'un souhaite une explication au-delà de ce qui suit, faites-le-moi savoir dans les commentaires.

Je vais commencer par les deux aspects qui génèrent l'appel à not-at .

* aka Whatever

De la page doc

Lorsque * est utilisé en position de terme, c'est-à-dire en tant qu'opérande, en combinaison avec la plupart des opérateurs, le compilateur transformera l'expression en une clôture de type WhateverCode

* est en effet utilisé dans ce qui précède comme opérande. Dans ce cas, il s'agit de l'argument de gauche (correspondant au paramètre $elems ) de l'opérateur not-at infixe que je viens de créer.

La prochaine question est: le compilateur effectuera-t-il la transformation? Le compilateur décide si l'opérateur a un * explicite comme paramètre correspondant à l'argument * . Si j'avais écrit * au lieu de $elems alors cela aurait rendu not-at l'un des rares opérateurs qui veulent gérer directement le * et faire ce qu'il veut et le compilateur l'appellerait directement. Mais je n'ai pas. J'ai écrit $elems . Donc, le compilateur effectue la transformation que je décrirai ensuite.

La transformation crée un nouveau WhateverCode autour de l'expression englobante et réécrit le Whatever comme "it", alias le sujet aka $_ place. Donc dans ce cas, cela devient:

* not-at (1,3,5)

dans ceci:

{ $_ not-at (1,3,5) }

Qu'est-ce que [...] en indice

Le [...] dans @a[...] est un indice Positional (tableau / liste). Cela impose plusieurs aspects d’évaluation, dont deux ici:

  • "it" aka le sujet aka $_ est défini sur la longueur de la liste / du tableau.

  • Si le contenu de l'indice est un Callable il est appelé. Le WhateverCode généré comme expliqué ci-dessus est effectivement un objet Callable sorte qu'il est appelé.

Donc ça:

@a[ * not-at (1,3,5) ]

devient ceci:

@a[ { $_ not-at [1,3,5] } ]

qui se transforme en ceci:

 @a[ { infix:not-at(7, [1,3,5]) } ]




deselect