通过索引从字符串中删除一些字符(Raku)


15

常见问题:在Raku中,如何根据字符串的索引从字符串中删除某些字符?

假设我要删除索引1至3和8

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

Answers:


14

Shnipersons的变体答案:

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

一行:

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

或由函数调用:

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

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

或增加Str:

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

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

我认为那完全解决了问题。感谢您提醒\和(-)是等效的。我看不到其他方式来分割想要的索引,而不是我想要的索引。
Tinmarino

1
您不必使用MONKET-TYPING它,只要使它成为自由浮动方法即可,并将其称为'foobar'.&remove: (1..2, 4); (如果多次使用,则增强会在合成方面出现问题)
user0721090601

(这并不是说扩充不好,刚才说的.&remove是一个方法来删除。
user0721090601

我为您的建议添加了非增强变体。谢谢。
塞巴斯蒂安

1
∖令人困惑,看起来像一个反斜杠字符。
Shniperson

12
.value.print if .key  !(elem) (1,2,3,8) for '0123456789'.comb.pairs

9

我最新的关于不正常操作的想法(我将在下面介绍实现):

用法:

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

实现,包装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

要使用的语法我已经声明是运营商string[- list-of-indices-to-be-subtracted ]使用熟悉的,即[...]符号,但在左边的字符串,并开放后的额外减[,表明标内容的列表exdices而不是指数

[编辑:我已经用Brad替换了原来的实现。正如布拉德(Brad)指出的那样,这可能是错误的,因为他的解决方案“假设[索引]从最低到最高是有序的,并且没有重叠。”,尽管他不答应,但使用[- ... ]却非常接近这样做。因此,如果某人使用此语法糖,那么他们可能不应该使用Brad的解决方案。也许有一种方法可以消除布拉德的假设。]

我喜欢这种语法,但我知道,拉里故意使用的建立[...]索引字符串,这样也许我在这里的语法是不合适的广泛采用。如果使用一些不同的包围字符,可能会更好。但是我认为使用简单的postcircumfix语法很好。

(我也曾尝试以[ ... ]Positionals 完全相同的方式为索引字符串实现一个直接变体,但由于今晚超出我的原因而未能使其正常工作。怪异的是,它[+ ... ]会做索引,但不做索引;这使得对我完全没有意义!无论如何,我将发布我的所有内容并认为此答案已完成。


[编辑:上面的解决方案有两个方面应被视为不同的方面。首先,一个用户定义的运算符,由postcircumfix:<[- ]> (Str ...声明提供的语法糖。第二,声明的正文。在上面,我使用了Brad解决方案(的一种变体)。我的原始答案如下。


因为您的问题可以归结为删除a的某些索引.combjoin显示结果,所以您的问题本质上是...的重复。 [编辑:错误,根据Brad的回答。]

取消选择数组或列表元素的快速方法是什么?.comb ... .join在此处为[ ]答案添加了更多解决方案。


实现为两个multi,因此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)

sort keys ^@pos (-) @exdices实现只是@Sebastian答案的稍微简化的版本。我还没有根据我上面链接的较早答案中的jnthn解决方案对它进行基准测试,但是如果速度更快,则可以将其替换。* [编辑:显然,它应该是布拉德针对字符串变体解决方案。] *


“我认为使用简单的postcircumfix语法很好”。绝对!我喜欢这种解决方案:超清晰阅读。
Tinmarino

8

另一个变体:

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

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

8

就简单性和简短性而言,这是我获得的最接近的结果。

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

7

每个人都可以使用comb或使用平面索引将字符串转换为列表。

没有理由做任何一件事情

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

上面假设索引的顺序是从最低到最高,并且没有重叠。


这是最快的答案,在我的机器上(带有my $s = "0123456789" x 1000; my $l = (1..3, 8, 40, 100, 1001, 4000..4100).flat)的150倍。梳子很长很长,谢谢@BradGilbert,这肯定会对某些人,至少对我有帮助:-)
Tinmarino

1
@Tinmarino这是因为MoarVM通常不复制字符串,而是创建指向原始字符串的子字符串对象。使用时,.comb它必须创建许多这些对象,并将它们重新组合在一起。使用substr它可以创建尽可能少的那些对象。
布拉德·吉尔伯特

“指向原始字符串的子字符串对象”:这就是为什么决定将Str实现为不可变的吗?无论如何,令人印象深刻的优化。
Tinmarino

5
my $string='0123456789';
for (1..3, 8).flat.reverse { $string.substr-rw($_, 1) = '' }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.