Usuń niektóre znaki z ciągu według indeksu (Raku)

15

FAQ: Jak w Raku usuwasz niektóre znaki z łańcucha na podstawie ich indeksu?

Powiedzmy, że chcę usunąć indeksy od 1 do 3 i 8

xxx("0123456789", (1..3, 8).flat);  # 045679
Tinmarino
źródło

Odpowiedzi:

14

Odpowiedź na wariant Shnipersonów:

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

W jednej linii:

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

lub wywoływane przez funkcję:

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

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

lub z rozszerzeniem Str:

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

say '0123456789'.remove: (1..3, 8);
Sebastian
źródło
To moim zdaniem całkowicie rozwiązuje problem. Dziękujemy za przypomnienie, że \ i (-) są równoważne. Nie widzę innych sposobów wycinania za pomocą indeksu, którego nie chcę, a nie indeksów, których chcę.
Tinmarino
1
Nie musisz go używać, MONKET-TYPINGjeśli po prostu uczynisz go metodą swobodną i wywołasz ją jako 'foobar'.&remove: (1..2, 4); (augmentacja może mieć problemy z kompozycją, jeśli zostanie użyta kilka razy)
user0721090601
(co nie znaczy, że rozszerzenie jest złe, po prostu .&removejest to sposób na usunięcie tego.
user0721090601
Do twojej sugestii dodałem wariant bez augmentacji. Dziękuję Ci.
Sebastian
1
∖ mylące i wydaje się być odwrotnym ukośnikiem.
Shniperson
12
.value.print if .key  !(elem) (1,2,3,8) for '0123456789'.comb.pairs
chenyf
źródło
9

Mój najnowszy pomysł na brak operacji (omówię implementację poniżej):

Stosowanie:

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

Wdrożenie, opakowanie (wariant) rozwiązania Brada:

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

Składnia do użycia operatora, który zadeklarowałem, polega na string[- list-of-indices-to-be-subtracted ]zastosowaniu znanej [...]notacji, ale z ciągiem po lewej stronie i dodatkowym minusem po otwarciu, [aby wskazać, że zawartość indeksu dolnego jest raczej listą ekscesów niż indeksów .

[Edytuj: Zastąpiłem moją oryginalną implementację wersją Brada. Prawdopodobnie jest to błędne, ponieważ, jak zauważa Brad, jego rozwiązanie „zakłada, że ​​[ekscesy] są w porządku od najniższego do najwyższego, i nie ma nakładania się”, a chociaż nie obiecuje inaczej, używanie [- ... ]jest okropnie bliskie robiąc tak. Więc jeśli ktoś miałby użyć tego cukru składniowego, prawdopodobnie nie powinien używać rozwiązania Brada. Być może istnieje sposób na wyeliminowanie założenia, które czyni Brad.]

Podoba mi się ta składnia, ale zdaję sobie sprawę, że Larry celowo nie budował w [...]celu indeksowania ciągów, więc być może moja składnia jest nieodpowiednia do powszechnego przyjmowania. Być może byłoby lepiej, gdyby zastosowano kilka różnych znaków nawiasowych. Ale myślę, że użycie prostej składni postcircumfix jest fajne.

(Próbowałem również zaimplementować prosty [ ... ]wariant do indeksowania ciągów w dokładnie taki sam sposób jak dla Positionals, ale nie udało mi się sprawić, aby działał z innych przyczyn niż dziś wieczorem. Dziwnie [+ ... ]będzie działał, aby robić exdices, ale nie indeksy; to sprawia, że nie ma dla mnie żadnego sensu! W każdym razie opublikuję to, co mam i uznam tę odpowiedź za kompletną).


[Edycja: Powyższe rozwiązanie ma dwa aspekty, które należy postrzegać jako odrębne. Po pierwsze, operator zdefiniowany przez użytkownika, cukier składniowy dostarczony przez postcircumfix:<[- ]> (Str ...deklarację. Po drugie, treść tej deklaracji. Powyżej użyłem (wariant) rozwiązania Brada. Moja oryginalna odpowiedź znajduje się poniżej.]


Ponieważ twoje pytanie sprowadza się do usunięcia niektórych wskaźników .combi odnosząc joinsię do wyniku, twoje pytanie jest zasadniczo duplikatem ... [Edytuj: Źle, na odpowiedź Brada].

Jaki jest szybki sposób na usunięcie zaznaczenia elementów tablicy lub listy? dodaje tutaj jeszcze więcej rozwiązań dla [ .comb ... .join] odpowiedzi.


Zaimplementowane jako dwa multis, więc ta sama składnia może być używana z 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 (-) @exdicesRealizacja jest po prostu nieco uproszczona wersja @ odpowiedź Sebastiana. Nie porównałem go z rozwiązaniem Jnthna z wcześniejszej odpowiedzi, którą podałem powyżej, ale jeśli jest to szybsze, można go wymienić. * [Edycja: Oczywiście powinno to być rozwiązanie Brada dla wariantu łańcucha.] *

raiph
źródło
„Myślę, że użycie prostej składni postcircumfix jest dobre”. Zdecydowanie ! Uwielbiam to rozwiązanie: super czytelne.
Tinmarino
8

jeszcze inne warianty:

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

.print for ((0..9) (-) (1,2,3,8)).keys;
Shniperson
źródło
8

To jest najbliższe pod względem prostoty i krótkości.

say '0123456789'.comb[ |(3..6), |(8..*) ].join
Holli
źródło
7

Wszyscy albo przekształcają ciąg znaków w listę, używając combpłaskiej listy indeksów lub używając tej listy.

Nie ma powodu, aby robić jedną z tych rzeczy

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

Powyższe zakłada, że ​​wskaźniki są uporządkowane od najniższego do najwyższego i nie ma nakładania się.

Brad Gilbert
źródło
To najszybsza odpowiedź 150 razy na moim komputerze (z my $s = "0123456789" x 1000; my $l = (1..3, 8, 40, 100, 1001, 4000..4100).flat). Grzebień jest długi na długie sznurki Dzięki @BradGilbert, to zdecydowanie pomoże niektórym ludziom, przynajmniej mnie :-)
Tinmarino
1
@ Tinmarino To dlatego, że MoarVM zwykle nie kopiuje ciągów, zamiast tego tworzy obiekty podciągów, które wskazują na oryginalny ciąg. Kiedy .combgo użyjesz, musisz utworzyć wiele z tych obiektów i połączyć je z powrotem. Dzięki substrniemu powstaje jak najmniej takich obiektów.
Brad Gilbert
„obiekty podłańcuchowe, które wskazują na oryginalny ciąg znaków”: czy dlatego postanowiono zaimplementować Str jako niezmienny? W każdym razie imponująca optymalizacja.
Tinmarino
5
my $string='0123456789';
for (1..3, 8).flat.reverse { $string.substr-rw($_, 1) = '' }
Sebastian
źródło