ゆくゆくは有へと

おかゆ/オカ∃/大鹿有生/彼ノ∅有生 の雑記

指定文字消すのどうすればいいんや

abc002.contest.atcoder.jp

“The Rust Programming Language” の第二版を最終章除いて読み終わったので、Atcoderでぽちぽちコード書く練習してるんだけど、 API全然知らないのでもうわっかんな~い(へらへら)

ありがたい………

qiita.com

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let mut word = buffer.trim().to_string();
    for ch in "aeiou".chars() {
        word = word.split(ch).collect::<Vec<_>>().concat();
    }
    println!("{}", word);
}

効率的な文字の消し方が分からんかったので、各母音字でsplitして集めてを繰り返すという微妙なやりかたをした。

調べてて気づいたが、collect::<Vec<_>>().concat() でなく、collect::<String>()にしたほうが賢いね。
collectFromIteratorトレイトのメソッドで、charイテレータStringにコレクトできるので。

というようなことを考えてると、for文消したくなるね。

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let word = buffer.trim().to_string();
    let word = "aeiou".chars().fold(word, |w, c| w.split(c).collect::<String>());
    println!("{}", word);
}

畳み込めばいいよね!ってことで畳み込んだ。

もう少し素朴なやりかた。containsStringpushをおぼえた。

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let mut word = String::new();
    for c in buffer.trim().chars() {
        if !['a', 'e', 'i', 'o', 'u'].contains(&c) {
            word.push(c)
        }
    }

    println!("{}", word);
}

&strcharの配列なりスライスではないので、if !['a', 'e', 'i', 'o', 'u'].contains(&c)と書かないといけないのがPythonマンのおかゆには厳しさがある。

if !"aeiou".chars().collect<Vec<_>>.contains(&c)とすればいけるけど。もっと簡単な書き方あるのかな~。

と色々書いてて思いついたけど、filter使えばいいのでは……?

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let word: String = buffer.trim()
                             .chars()
                             .filter(|c| !['a', 'e', 'i', 'o', 'u'].contains(&c))
                             .collect();
    println!("{}", word);
}

やっぱイテレータ触るならチェーンやで……!といわんばかりのチェーン 単語を文字のイテレータにして、子音だけパスしてコレクト。リストの内包表記こそ使えないものの、それにいちばん近いのは今までの中ならこれかな?

Pythonでなら、多分こう書くもんな:

word = "".join([c for c in word if c not in "aeiou"])
print(word)

f:id:waraby0ginger:20170807012446j:plain

追記(2017/8/7/20:05):replace あるやんけ

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let word: String = buffer.trim()
                             .replace(&['a', 'e', 'i', 'o', 'u'][..], "");
    println!("{}", word);
}

あれからstrのこと調べてると、スライスとstrcontains, starts_with, ends_with, find, split系の引数が違うらしいことを知った。

strでは、要素1つの代わりにパターン(Patternトレイトを実装している型)を取るらしい:

  • &String
  • &[char]
  • char
  • FnMut(char) -> bool
  • &&str
  • &str

文字1文字はもちろんのこと、部分文字列やら、char.is_numericといった関数も与えれるので、結構柔軟にパターンが作れるらしい。

特に、&[char]論理和(って言い方であってんのか)なので便利…。

ちなみにおかゆは .replace(&['a', 'e', 'i', 'o', 'u'], "") ってして「&[char; 5]はダメっぷ~~~~ww」ってコンパイラに言われてキレてたんですけど、
ジェネリクスのトレイトバウンドの箇所では諸々の型強制(今回だとunsize coercion)が効かないの忘れてた(てへぺろ

Coercions -

こういう場面で型強制効かないのって安全のため?なんだろうけど、トレイトバウンドに使うときに融通の効くトレイトを作るのって結構大変そうだね。