Entfernen Sie einige Zeichen aus einer Zeichenfolge nach Index (Raku).

15

FAQ: Wie können Sie in Raku einige Zeichen basierend auf ihrem Index aus einer Zeichenfolge entfernen?

Angenommen, ich möchte die Indizes 1 bis 3 und 8 entfernen

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

Antworten:

14

Variante von Shnipersons Antwort:

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

In einer Zeile:

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

oder von einer Funktion aufgerufen:

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

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

oder mit Augmentation von Str:

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

say '0123456789'.remove: (1..3, 8);
Sebastian
quelle
Das löst das Problem meiner Meinung nach vollständig. Vielen Dank, dass Sie daran erinnert haben, dass \ und (-) gleichwertig sind. Ich sehe keine anderen Möglichkeiten, mit dem Index, den ich nicht möchte, und nicht mit den Indizes, die ich möchte, zu schneiden .
Tinmarino
1
Sie müssen es nicht verwenden, MONKET-TYPINGwenn Sie es einfach als frei schwebende Methode verwenden und es als 'foobar'.&remove: (1..2, 4); (Augment kann Probleme mit der Komposition haben, wenn es mehrmals verwendet wird)
aufrufen
(was nicht heißt, dass Augment schlecht ist, nur dass dies .&removeein Weg ist, dies zu entfernen.
user0721090601
Ich habe die Nicht-Augmentationsvariante zu Ihrem Vorschlag hinzugefügt. Vielen Dank.
Sebastian
1
∖ verwirrend und wirkt wie ein Backslash-Charakter.
Shniperson
12
.value.print if .key  !(elem) (1,2,3,8) for '0123456789'.comb.pairs
Chenyf
quelle
9

Meine neueste Idee für eine Nicht-At-Operation (ich werde die Implementierung unten behandeln):

Verwendungszweck:

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

Implementierung, Verpackung (eine Variante von) Brads Lösung:

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

Die Syntax zur Verwendung des von mir deklarierten Operators lautet string[- list-of-indices-to-be-subtracted ], dh unter Verwendung der bekannten [...]Notation, jedoch mit einer Zeichenfolge links und einem zusätzlichen Minus nach dem Öffnen, [um anzuzeigen, dass der tiefgestellte Inhalt eine Liste von Exdices und keine Indizes ist .

[Bearbeiten: Ich habe meine ursprüngliche Implementierung durch die von Brad ersetzt. Das ist wahrscheinlich falsch, weil, wie Brad bemerkt, seine Lösung "davon ausgeht, dass die [Exdices] in der Reihenfolge vom niedrigsten zum höchsten sind und es keine Überlappung gibt.", Und obwohl er nichts anderes verspricht, ist die Verwendung [- ... ]furchtbar nahe dabei. Wenn also dieser Syntaxzucker von jemandem verwendet werden soll, sollte er wahrscheinlich nicht Brads Lösung verwenden. Vielleicht gibt es einen Weg, die Annahme zu beseitigen, die Brad macht.]

Ich mag diese Syntax , aber bin mir bewusst , dass Larry bewusst habe nicht in Verwendung bauen [...]so vielleicht zu indizieren Strings meine Syntax ist hier ungeeignet für weit verbreitete Annahme. Vielleicht wäre es besser, wenn verschiedene Klammerzeichen verwendet würden. Aber ich denke, die Verwendung einer einfachen Postcircumfix-Syntax ist nett.

(Ich habe auch versucht, eine gerade [ ... ]Variante für die Indizierung von Zeichenfolgen genauso zu implementieren wie für Positionals, aber ich habe es aus Gründen, die ich heute Abend [+ ... ]nicht kenne, nicht zum Laufen gebracht . Seltsamerweise wird es funktionieren, Exdices zu machen, aber keine Indizes; das macht Für mich macht das überhaupt keinen Sinn! Wie auch immer, ich werde posten, was ich habe und diese Antwort als vollständig betrachten.)


[Bearbeiten: Die obige Lösung hat zwei Aspekte, die als unterschiedlich angesehen werden sollten. Zunächst ein benutzerdefinierter Operator, der syntaktische Zucker, der durch die postcircumfix:<[- ]> (Str ...Deklaration bereitgestellt wird . Zweitens der Hauptteil dieser Erklärung. Oben habe ich (eine Variante von) Brads Lösung verwendet. Meine ursprüngliche Antwort ist unten.]


Da Ihre Frage darauf hinausläuft, einige Indizes von a zu entfernen .combund joindas Ergebnis zu überprüfen, ist Ihre Frage im Wesentlichen ein Duplikat von ... [Bearbeiten: Falsch, gemäß Brads Antwort.]

Was ist eine schnelle Möglichkeit, Array- oder Listenelemente abzuwählen? fügt hier noch weitere Lösungen für die [ .comb ... .join] Antworten hinzu.


Implementiert als zwei Multis, sodass dieselbe Syntax mit Positionals verwendet werden kann:

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)

Die sort keys ^@pos (-) @exdicesImplementierung ist nur eine leicht vereinfachte Version von @ Sebastians Antwort. Ich habe es nicht mit jnthns Lösung aus der früheren Antwort verglichen, die ich oben verlinkt habe, aber wenn das schneller ist, kann es stattdessen ausgetauscht werden. * [Bearbeiten: Natürlich sollte es stattdessen Brads Lösung für die String-Variante sein.] *

Raiph
quelle
"Ich finde die Verwendung einer einfachen Postcircumfix-Syntax nett". Bestimmt ! Ich liebe diese Lösung: super klar zu lesen.
Tinmarino
8

noch eine andere 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
quelle
8

Dies ist das Beste, was ich in Bezug auf Einfachheit und Kürze erreicht habe.

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

Jeder verwandelt die Zeichenfolge entweder mithilfe comboder unter Verwendung einer flachen Liste von Indizes in eine Liste .

Es gibt keinen Grund, eines dieser Dinge zu tun

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

Das Obige setzt voraus, dass die Indizes in der Reihenfolge vom niedrigsten zum höchsten sind und es keine Überlappung gibt.

Brad Gilbert
quelle
Dies ist die um den Faktor 150 schnellste Antwort auf meinem Computer (mit my $s = "0123456789" x 1000; my $l = (1..3, 8, 40, 100, 1001, 4000..4100).flat). Kamm ist lang für lange Saiten Danke @BradGilbert, das wird definitiv einigen Leuten helfen, zumindest mir :-)
Tinmarino
1
@Tinmarino Das liegt daran, dass MoarVM normalerweise keine Zeichenfolgen kopiert, sondern Teilzeichenfolgenobjekte erstellt, die auf die ursprüngliche Zeichenfolge verweisen. Wenn Sie es verwenden, müssen .combSie viele dieser Objekte erstellen und sie wieder miteinander kombinieren. Damit substrentstehen möglichst wenige dieser Objekte.
Brad Gilbert
"Teilstring-Objekte, die auf die ursprüngliche Zeichenfolge zeigen": Wurde deshalb beschlossen, Str als unveränderlich zu implementieren? Trotzdem beeindruckende Optimierung.
Tinmarino
5
my $string='0123456789';
for (1..3, 8).flat.reverse { $string.substr-rw($_, 1) = '' }
Sebastian
quelle