¿Cómo divido agradable / idiomáticamente una cadena en una lista de posiciones?
Lo que tengo:
.say for split-at( "0019ABX26002", (3, 4, 8) );
sub split-at( $s, @positions )
{
my $done = 0;
gather
{
for @positions -> $p
{
take $s.substr($done, $p - $done );
$done = $p;
}
take $s.substr( $done, * );
}
}
Lo cual es razonable. Sin embargo, estoy desconcertado por la falta de soporte de idiomas para esto. Si "dividir en" es una cosa, ¿por qué no "dividir en" también? Creo que esto debería ser una operación central. Debería poder escribir
.say for "0019ABX26002".split( :at(3, 4, 8) );
¿O tal vez estoy pasando por alto algo?
Editar: un pequeño punto de referencia de lo que tenemos hasta ahora
O------------O---------O------------O--------O-------O-------O
| | Rate | array-push | holli | raiph | simon |
O============O=========O============O========O=======O=======O
| array-push | 15907/s | -- | -59% | -100% | -91% |
| holli | 9858/s | 142% | -- | -100% | -79% |
| raiph | 72.8/s | 50185% | 20720% | -- | 4335% |
| simon | 2901/s | 1034% | 369% | -98% | -- |
O------------O---------O------------O--------O-------O-------O
Código:
use Bench;
my $s = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccddddddddddddddddddddddddddddddddddddefggggggggggggggggggg";
my @p = 29, 65, 69, 105, 106, 107;
Bench.new.cmpthese(1000, {
holli => sub { my @ = holli($s, @p); },
simon => sub { my @ = simon($s, @p); },
raiph => sub { my @ = raiph($s, @p); },
array-push => sub { my @ = array-push($s, @p); },
});
#say user($s, @p);
sub simon($str, *@idxs ) {
my @rotors = @idxs.map( { state $l = 0; my $o = $_ - $l; $l = $_; $o } );
$str.comb("").rotor( |@rotors,* ).map(*.join(""));
}
sub raiph($s, @p) {
$s.split( / <?{$/.pos == any(@p)}> / )
}
sub holli( $s, @positions )
{
my $done = 0;
gather
{
for @positions -> $p
{
take $s.substr($done, $p - $done );
$done = $p;
}
take $s.substr( $done, * );
}
}
sub array-push( $s, @positions )
{
my $done = 0;
my @result;
for @positions -> $p
{
@result.push: $s.substr($done, $p - $done );
$done = $p;
}
@result.push: $s.substr( $done, * );
@result;
}
("001", "9", "ABX2", "6002")
?Respuestas:
Personalmente lo dividiría en una lista, utilizo
rotor
para dividir la lista y unir el resultado:Si desea una división en la función (usando los índices dados):
Básicamente, si quiero hacer cosas de tipo de lista, uso una lista.
Se me ocurrió otra versión que realmente me gusta por un sentido de programación funcional:
Resulta ser un poco más lento que el otro.
fuente
rotor
. En este caso, sin embargo. Estás haciendo mucho trabajo para lo que debería ser una operación simple.De una sola mano:
muestra:
fuente
== 3|4|8
con el∈ @pos
de mejorar la velocidad. (Y algunos podrían preferir la forma en que se lee también.)Debido a que cada subcadena no depende de la otra, hiper se convierte en una opción.
O en forma secundaria:
Pero la sobrecarga involucrada no vale la pena a menos que la cantidad de elementos solicitados sea extrema: en mis pruebas es aproximadamente diez veces más lenta que la forma ingenua.
fuente
Aquí está la solución que usaría:
El
gather
/take
permite que sea flojo si finalmente no necesita usarlos todos. El bucle toma@i
(2,3,4
en el ejemplo) y lo cierra con el reductor de adición en cascada[\+]
, que normalmente produciría2,5,9
, pero insertamos un 00,2,5,9
para marcar los índices iniciales de cada uno. Esto permite que la toma real sea simplesubstr
operación .Al convertirlo
method
en un sub en lugar de un sub, puede usarlo como lo haría (incluso podría nombrarlosplit
si lo desea, la adición de&
sigilo significa que Raku no se confundirá si desea el incorporado o personalizado.Incluso podría agregarlo directamente a Str:
En este caso, debe definirse como
multi method
ya existen variossplit
métodos. Lo bueno es que, dado que ninguno de esos se define solo porInt
argumentos, es fácil asegurarse de que se use nuestro aumentado.Dicho esto, llamarlo usando la versión sigulada en un léxico
method
es definitivamente la mejor.fuente
:at
parámetro con nombre, lo actualizaré para hacerlo.split
. Tal sería una adición razonable, en mi humilde opinión.comb
lugar de ensplit
, ya que el peine ya está diseñado para trabajar en números enteros. ¿Qué tal esto? tio.run/##VVLJasMwFLz7KwYTgk1dZyn0kODQaw@FQo4lLbIs26LygiTThCy/…