Eliminar algunos caracteres de una cadena por índice (Raku)

15

Preguntas frecuentes: en Raku, ¿cómo eliminas algunos caracteres de una cadena, según su índice?

Digamos que quiero eliminar los índices 1 a 3 y 8

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

Respuestas:

14

La variante de Shnipersons responde:

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

En una linea:

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

o llamado por una función:

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

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

o con aumento de Str:

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

say '0123456789'.remove: (1..3, 8);
Sebastian
fuente
Eso resuelve el problema completamente en mi opinión. Gracias por recordar que \ y (-) son equivalentes. No veo otras formas de dividir el índice que no quiero y no los índices que quiero.
Tinmarino
1
No tiene que usarlo MONKET-TYPINGsi solo lo hace un método de flotación libre y lo llama como 'foobar'.&remove: (1..2, 4); (el aumento puede tener problemas con la composición si se usa varias veces)
user0721090601
(lo que no quiere decir que el aumento sea malo, solo que .&removees una forma de eliminarlo.
user0721090601
Agregué la variante sin aumento en cuanto a su sugerencia. Gracias.
Sebastian
1
∖ confuso y parece un carácter de barra invertida.
Shniperson
12
.value.print if .key  !(elem) (1,2,3,8) for '0123456789'.comb.pairs
chenyf
fuente
9

Mi última idea para una operación de no-at (cubriré la implementación a continuación):

Uso:

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

Implementación, envoltura (una variante de) la solución 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 sintaxis para usar el operador que he declarado es string[- list-of-indices-to-be-subtracted ], es decir, usar una [...]notación familiar , pero con una cadena a la izquierda y un signo menos después de la apertura [para indicar que el contenido del subíndice es una lista de exdices en lugar de índices. .

[Editar: he reemplazado mi implementación original con la de Brad. Probablemente sea erróneo porque, como señala Brad, su solución "asume que los [exdices] están en orden de más bajo a más alto, y no hay superposición", y aunque el suyo no promete lo contrario, el uso [- ... ]es muy cercano a haciéndolo. Entonces, si alguien usara esta sintaxis, probablemente no debería usar la solución de Brad. Quizás haya una manera de eliminar la suposición de Brad.]

Me gusta esta sintaxis, pero sé que Larry lo hizo deliberadamente no creó el uso [...]para indexar cadenas, por lo que tal vez mi sintaxis aquí sea inapropiada para una adopción generalizada. Quizás sería mejor si se usaran algunos caracteres de horquillado diferentes. Pero creo que el uso de una sintaxis simple postcircumfix es bueno.

(También he intentado implementar una [ ... ]variante directa para indexar cadenas exactamente de la misma manera que para Positionals, pero no he logrado que funcione por razones ajenas a mí esta noche.[+ ... ] trabajaré para hacer exdices pero no para hacer índices; eso hace que ¡No tiene ningún sentido para mí! De todos modos, publicaré lo que tengo y consideraré esta respuesta completa.)


[Editar: La solución anterior tiene dos aspectos que deberían verse como distintos. Primero, un operador definido por el usuario, el azúcar sintáctico proporcionado por elpostcircumfix:<[- ]> (Str ... declaración. En segundo lugar, el cuerpo de esa declaración. En lo anterior, he usado (una variante de) la solución de Brad. Mi respuesta original está abajo.]


Debido a que su pregunta se reduce a eliminar algunos índices de a .comb, y obtener joinel resultado, su pregunta es esencialmente un duplicado de ... [Editar: Incorrecto, según la respuesta de Brad.]

¿Cuál es una forma rápida de deseleccionar la matriz o elementos de la lista?agrega aún más soluciones para el [.comb ... .join respuestas ] aquí.


Implementado como dos multis para que la misma sintaxis se pueda usar con Positional s:

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)

La sort keys ^@pos (-) @exdicesimplementación es solo una versión ligeramente simplificada de la respuesta de @ Sebastian. No lo he comparado con la solución de jnthn de la respuesta anterior que vinculé anteriormente, pero si eso es más rápido, entonces se puede intercambiar. * [Editar: Obviamente, debería ser la solución de Brad para la variante de cadena.] *

raiph
fuente
"Creo que el uso de una sintaxis simple postcircumfix es bueno". Definitivamente! Me encanta esta solución: super claro para leer.
Tinmarino
8

otras variantes más:

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

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

Esto es lo más cercano que obtuve en términos de simplicidad y brevedad.

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

Todos están convirtiendo la cadena en una lista usando combo usando una lista plana de índices.

No hay razón para hacer ninguna de esas cosas.

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

Lo anterior supone que los índices están en orden de menor a mayor, y no hay superposición.

Brad Gilbert
fuente
Esta es la respuesta más rápida por un factor de 150 en mi máquina (con my $s = "0123456789" x 1000; my $l = (1..3, 8, 40, 100, 1001, 4000..4100).flat). El peine es largo para largas cadenas Gracias @BradGilbert, esto definitivamente ayudará a algunas personas, al menos a mí :-)
Tinmarino
1
@Tinmarino Esto se debe a que MoarVM no suele copiar cadenas, sino que crea objetos de subcadenas que apuntan a la cadena original. Cuando lo usa .combtiene que crear muchos de esos objetos y combinarlos nuevamente. Con substresto crea la menor cantidad posible de esos objetos.
Brad Gilbert
"objetos de subcadena que apuntan a la cadena original": ¿es por eso que se decidió implementar Str como inmutable? Impresionante optimización de todos modos.
Tinmarino
5
my $string='0123456789';
for (1..3, 8).flat.reverse { $string.substr-rw($_, 1) = '' }
Sebastian
fuente