Supprimer certains caractères d'une chaîne par index (Raku)

15

FAQ: Dans Raku, comment supprimez-vous certains caractères d'une chaîne, en fonction de leur index?

Dis que je veux supprimer les indices 1 à 3 et 8

xxx("0123456789", (1..3, 8).flat);  # 045679
Tinmarino
la source

Réponses:

14

Variante de Shnipersons réponse:

my $a='0123456789';
with $a {$_=.comb[(^* ∖ (1..3, 8).flat).keys.sort].join};
say $a;

En une seule ligne:

say '0123456789'.comb[(^* ∖ (1..3, 8).flat).keys.sort].join;

ou appelé par une fonction:

sub remove($str, $a) {
    $str.comb[(^* ∖ $a.flat).keys.sort].join;
}

say '0123456789'.&remove: (1..3, 8);

ou avec augmentation de Str:

use MONKEY-TYPING;
augment class Str {
    method remove($a) {
        $.comb[(^* ∖ $a.flat).keys.sort].join;
    }
};

say '0123456789'.remove: (1..3, 8);
Sébastien
la source
À mon avis, cela résout complètement le problème. Merci d'avoir rappelé que \ et (-) sont équivalents. Je ne vois pas d'autres façons de découper avec l'index que je ne veux pas et pas avec les indices que je veux.
Tinmarino
1
Vous n'êtes pas obligé de l'utiliser MONKET-TYPINGsi vous le rendez juste une méthode flottante gratuite et l'appelez comme 'foobar'.&remove: (1..2, 4); (l'augmentation peut avoir des problèmes de composition si elle est utilisée plusieurs fois)
user0721090601
(ce qui ne veut pas dire que l'augmentation est mauvaise, c'est juste que .&removec'est un moyen de supprimer cela.
user0721090601
J'ai ajouté la variante sans augmentation à votre suggestion. Je vous remercie.
Sebastian
1
∖ déroutant et ressemble à une barre oblique inverse.
Shniperson
12
.value.print if .key  !(elem) (1,2,3,8) for '0123456789'.comb.pairs
chenyf
la source
9

Ma dernière idée pour une opération non-at (je couvrirai la mise en œuvre ci-dessous):

Usage:

say '0123456789'[- 1..3, 8 ]; # 045679

Implémentation, emballage (une variante de) la solution de Brad:

multi postcircumfix:<[- ]> (|args) { remove |args }

sub remove( Str:D $str is copy, +@exdices){
    for @exdices.reverse {
        when Int   { $str.substr-rw($_,1) = '' }
        when Range { $str.substr-rw($_  ) = '' }
    }
    $str
}

say '0123456789'[- 1..3, 8 ]; # 045679

La syntaxe pour utiliser l'opérateur que j'ai déclaré est string[- list-of-indices-to-be-subtracted ], c'est-à-dire en utilisant une [...]notation familière , mais avec une chaîne à gauche et un moins supplémentaire après l'ouverture [pour indiquer que le contenu de l'indice est une liste d' exdices plutôt que des indices .

[Modifier: j'ai remplacé mon implémentation d'origine par celle de Brad. C'est probablement faux parce que, comme le note Brad, sa solution "suppose que les [exdices] sont dans l'ordre du plus bas au plus élevé, et il n'y a pas de chevauchement.", Et bien que son ne promette pas le contraire, l'utilisation [- ... ]est terriblement proche de Ce faisant. Donc, si ce sucre de syntaxe devait être utilisé par quelqu'un, il ne devrait probablement pas utiliser la solution de Brad. Il y a peut-être un moyen d'éliminer l'hypothèse de Brad.]

J'aime cette syntaxe, mais je suis conscient que Larry n'a pas délibérément construit en utilisant [...]pour indexer des chaînes, alors peut-être que ma syntaxe ici n'est pas appropriée pour une adoption généralisée. Il serait peut-être préférable d'utiliser des caractères de bracketing différents. Mais je pense que l'utilisation d'une simple syntaxe postcircumfix est agréable.

(J'ai également essayé d'implémenter une [ ... ]variante directe pour l'indexation de chaînes exactement de la même manière que pour Positionals mais je n'ai pas réussi à le faire fonctionner pour des raisons qui me dépassent ce soir. Bizarrement, [+ ... ]cela fonctionnera pour faire des exdices mais pas des index; cela fait aucun sens pour moi! Quoi qu'il en soit, je vais publier ce que j'ai et considérer cette réponse comme complète.)


[Edit: La solution ci-dessus a deux aspects qui doivent être considérés comme distincts. Tout d'abord, un opérateur défini par l'utilisateur, le sucre syntaxique fourni par la postcircumfix:<[- ]> (Str ...déclaration,. Deuxièmement, le corps de cette déclaration. Dans ce qui précède, j'ai utilisé (une variante de) la solution de Brad. Ma réponse originale est ci-dessous.]


Parce que votre question se résume à la suppression de certains indices de a .combet joinau résultat, votre question est essentiellement un double de ... [Edit: Wrong, per Brad's answer.]

Quel est un moyen rapide de désélectionner des éléments de tableau ou de liste? ajoute encore plus de solutions pour les .comb ... .joinréponses [ ] ici.


Implémenté en deux multis afin que la même syntaxe puisse être utilisée avec Positionals:

multi postcircumfix:<[- ]> (Str $_, *@exdex) { .comb[- @exdex ].join }

multi postcircumfix:<[- ]> (@pos,   *@exdex) { sort keys ^@pos (-) @exdex } 

say '0123456789'[- 1..3, 8 ]; # 045679

say (0..9)[- 1..3, 8 ];       # (0 4 5 6 7 9)

L' sort keys ^@pos (-) @exdicesimplémentation n'est qu'une version légèrement simplifiée de la réponse de @ Sebastian. Je ne l'ai pas comparé à la solution de jnthn de la réponse précédente que j'ai liée ci-dessus, mais si c'est plus rapide, il peut être échangé à la place. * [Edit: Evidemment, ce devrait plutôt être la solution de Brad pour la variante de chaîne.] *

raiph
la source
"Je pense que l'utilisation d'une simple syntaxe postcircumfix est agréable". Absolument ! J'adore cette solution: super clair à lire.
Tinmarino
8

encore une autre variante:

print $_[1] if $_[0] !(elem) (1,2,3,8) for ^Inf Z 0..9;

.print for ((0..9) (-) (1,2,3,8)).keys;
Shniperson
la source
8

C'est le plus proche que j'ai obtenu en termes de simplicité et de brièveté.

say '0123456789'.comb[ |(3..6), |(8..*) ].join
Holli
la source
7

Tout le monde transforme la chaîne en liste en utilisant combou en utilisant une liste plate d'index.

Il n'y a aucune raison de faire l'une ou l'autre de ces choses

sub remove( Str:D $str is copy, +@indices ){
    for @indices.reverse {
        when Int   { $str.substr-rw($_,1) = '' }
        when Range { $str.substr-rw($_  ) = '' }
    }
}

remove("0123456789",  1..3, 8 );  # 045679
remove("0123456789", [1..3, 8]);  # 045679

Ce qui précède suppose que les indices sont dans l'ordre du plus bas au plus élevé, et qu'il n'y a pas de chevauchement.

Brad Gilbert
la source
C'est la réponse la plus rapide d'un facteur 150 sur ma machine (avec my $s = "0123456789" x 1000; my $l = (1..3, 8, 40, 100, 1001, 4000..4100).flat). Le peigne est long pour de longues cordes Merci @BradGilbert, cela aidera certainement certaines personnes, au moins moi :-)
Tinmarino
1
@Tinmarino En effet, MoarVM ne copie généralement pas de chaînes, mais crée des objets de sous-chaîne qui pointent dans la chaîne d'origine. Lorsque vous l'utilisez, vous devez .combcréer un grand nombre de ces objets et les regrouper. Avec substrcela, il crée le moins possible de ces objets.
Brad Gilbert
"sous-chaîne d'objets qui pointent dans la chaîne d'origine": est-ce pour cela qu'il a été décidé d'implémenter Str comme immuable? Optimisation impressionnante de toute façon.
Tinmarino
5
my $string='0123456789';
for (1..3, 8).flat.reverse { $string.substr-rw($_, 1) = '' }
Sébastien
la source