Hapus beberapa karakter dari string dengan indeks (Raku)

15

FAQ: Di Raku, bagaimana Anda menghapus beberapa karakter dari string, berdasarkan indeks mereka?

Katakanlah saya ingin menghapus indeks 1 hingga 3 dan 8

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

Jawaban:

14

Varian jawaban Shnipersons:

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

Dalam satu baris:

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

atau disebut dengan fungsi:

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

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

atau dengan augmentasi Str:

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

say '0123456789'.remove: (1..3, 8);
Sebastian
sumber
Itu menyelesaikan masalah sepenuhnya menurut saya. Terima kasih telah mengingatkan bahwa \ dan (-) sama. Saya tidak melihat cara lain untuk memotong dengan indeks yang tidak saya inginkan dan bukan indeks yang saya inginkan.
Tinmarino
1
Anda tidak harus menggunakan MONKET-TYPINGjika Anda hanya membuatnya metode mengambang bebas dan menyebutnya sebagai 'foobar'.&remove: (1..2, 4); (augment dapat memiliki masalah dengan komposisi jika digunakan beberapa kali)
user0721090601
(yang tidak berarti penambahan itu buruk, hanya saja itu .&removecara untuk menghapusnya.
user0721090601
Saya menambahkan varian non-augmentasi sebagai saran Anda. Terima kasih.
Sebastian
1
∖ membingungkan dan sepertinya karakter backslash.
Shniperson
12
.value.print if .key  !(elem) (1,2,3,8) for '0123456789'.comb.pairs
chenyf
sumber
9

Gagasan terbaru saya untuk tidak-beroperasi (saya akan membahas implementasi di bawah):

Pemakaian:

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

Implementasi, pembungkus (varian) solusi 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

Sintaks untuk menggunakan operator yang telah saya nyatakan adalah string[- list-of-indices-to-be-subtracted ], yaitu menggunakan [...]notasi yang umum , tetapi dengan string di sebelah kiri dan minus tambahan setelah pembukaan [untuk menunjukkan bahwa konten subskrip adalah daftar exdices daripada indeks .

[Sunting: Saya telah mengganti implementasi asli saya dengan Brad. Itu mungkin salah arah karena, seperti yang dicatat Brad, solusinya "mengasumsikan bahwa [pengeluaran] dalam urutan dari terendah ke tertinggi, dan tidak ada tumpang tindih.", Dan sementara itu tidak menjanjikan sebaliknya, menggunakan [- ... ]sangat dekat dengan melakukannya. Jadi jika gula sintaks ini digunakan oleh seseorang, mereka mungkin tidak boleh menggunakan solusi Brad. Mungkin ada cara untuk menghilangkan anggapan yang dibuat Brad.]

Saya suka sintaks ini tetapi saya sadar bahwa Larry sengaja tidak membangun [...]untuk mengindeks string jadi mungkin sintaks saya di sini tidak pantas untuk adopsi luas. Mungkin akan lebih baik jika beberapa karakter tanda kurung yang berbeda digunakan. Tapi saya pikir penggunaan sintaks postcircumfix sederhana itu bagus.

(Saya juga mencoba menerapkan [ ... ]varian langsung untuk string pengindeksan dengan cara yang persis sama seperti untuk Positionals tetapi gagal membuatnya berfungsi karena alasan di luar saya malam ini. Aneh [+ ... ]akan bekerja untuk melakukan exdices tetapi tidak untuk melakukan indeks; yang membuat sama sekali tidak masuk akal bagi saya! Bagaimanapun, saya akan memposting apa yang saya miliki dan menganggap jawaban ini lengkap.)


[Sunting: Solusi di atas memiliki dua aspek yang harus dilihat sebagai berbeda. Pertama, operator yang ditentukan pengguna, gula sintaksis yang disediakan oleh postcircumfix:<[- ]> (Str ...deklarasi. Kedua, badan deklarasi itu. Di atas saya telah menggunakan (varian) solusi Brad. Jawaban asli saya di bawah.]


Karena pertanyaan Anda bermuara pada menghapus beberapa indeks dari .comb, dan mengembalikan joinhasilnya, pertanyaan Anda pada dasarnya adalah duplikat dari ... [Sunting: Salah, sesuai jawaban Brad.]

Apa cara cepat untuk menghilangkan elemen array atau daftar? menambahkan lebih banyak solusi untuk .comb ... .joinjawaban [ ] di sini.


Diimplementasikan sebagai dua multis sehingga sintaks yang sama dapat digunakan dengan 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)

The sort keys ^@pos (-) @exdicesimplementasi adalah hanya sedikit versi sederhana dari @ jawaban Sebastian. Saya belum membandingkannya dengan solusi jnthn dari jawaban sebelumnya yang saya tautkan di atas, tetapi jika itu lebih cepat maka dapat ditukar sebagai gantinya. * [Sunting: Jelas itu seharusnya menjadi solusi Brad untuk varian string.] *

raiph
sumber
"Saya pikir penggunaan sintaks postcircumfix sederhana itu bagus". Pastinya ! Saya suka solusi ini: sangat jelas untuk dibaca.
Tinmarino
8

varian lain:

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

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

Ini adalah yang paling dekat yang saya dapatkan dalam hal kesederhanaan dan kekurangan.

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

Setiap orang mengubah string menjadi daftar menggunakan combatau menggunakan daftar indeks datar.

Tidak ada alasan untuk melakukan hal-hal itu

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

Di atas mengasumsikan bahwa indeks berada dalam urutan dari terendah ke tertinggi, dan tidak ada tumpang tindih.

Brad Gilbert
sumber
Ini adalah jawaban tercepat dengan faktor 150 pada mesin saya (dengan my $s = "0123456789" x 1000; my $l = (1..3, 8, 40, 100, 1001, 4000..4100).flat). Sisir panjang untuk string panjang Terima kasih @BradGilbert, ini pasti akan membantu beberapa orang, setidaknya saya :-)
Tinmarino
1
@Tinmarino Itu karena MoarVM biasanya tidak menyalin string, melainkan menciptakan objek substring yang mengarah ke string asli. Ketika Anda menggunakannya .combharus membuat banyak objek tersebut, dan menggabungkannya kembali. Dengan substritu menciptakan objek-objek tersebut sesedikit mungkin.
Brad Gilbert
"substring objek yang mengarah ke string asli": apakah itu sebabnya diputuskan untuk mengimplementasikan Str sebagai tidak dapat diubah? Optimalisasi yang mengesankan.
Tinmarino
5
my $string='0123456789';
for (1..3, 8).flat.reverse { $string.substr-rw($_, 1) = '' }
Sebastian
sumber