Rustのコレクション(練習問題)
Vec, String, HashMap。
成果物
参考
以下をヒントに解いた。
- https://doc.rust-lang.org/std/vec/struct.Vec.html
- https://doc.rust-lang.org/std/string/struct.String.html
- https://doc.rust-lang.org/beta/std/collections/struct.HashMap.html
- https://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html
- https://stackoverflow.com/questions/55080089/converting-i32-to-f64
- https://users.rust-lang.org/t/hashmap-with-vector-values/17906
コード
Vec
問題。
整数のリストが与えられ、ベクタを使ってmean(平均値)、median(ソートされた時に真ん中に来る値)、 mode(最も頻繁に出現する値; ハッシュマップがここでは有効活用できるでしょう)を返してください。
解答。
fn main() { let v = vec![5, 2, 7, 1, 3, 2, 9]; println!("vec: {:?}", v); println!("mean: {}", mean(&v)); println!("median: {}", median(&v)); println!("mode: {}", mode(&v)); } // 平均 fn mean(v: &Vec<i32>) -> f64 { let mut sum: f64 = 0.0; for i in v { sum += f64::from(*i); // https://stackoverflow.com/questions/55080089/converting-i32-to-f64 } sum / v.len() as f64 } // ソート時の中央値 fn median(v: &Vec<i32>) -> i32 { let mut s = Vec::new(); for i in v { s.push(i); } s.sort(); **s.get(s.len()/2).unwrap() } // 頻出値 fn mode(v: &Vec<i32>) -> i32 { use std::collections::HashMap; let mut h = HashMap::new(); for i in v { let count = h.entry(i).or_insert(0); *count += 1; } let mut mode = 0; let mut max_count = 0; for (key, value) in h { if max_count < value { max_count = value; mode = *key; } } mode }
f64::from(*i)
, as f64
など型の変換・統一がポイント。これは未学習だった。ググって知った。
String
問題。
文字列をピッグ・ラテン(訳注: 英語の言葉遊びの一つ)に変換してください。各単語の最初の子音は、 単語の終端に移り、"ay"が足されます。従って、"first"は"irst-fay"になります。ただし、 母音で始まる単語には、お尻に"hay"が付け足されます("apple"は"apple-hay"になります)。 UTF-8エンコードに関する詳細を心に留めておいてください!
解答。
fn main() { println!("{}", pig_latin("first")); println!("{}", pig_latin("apple")); } fn pig_latin(s: &str) -> String { let mut pig = String::from(s); let vowels = ['a','i','u','e','o']; // 母音 match s.chars().nth(0).unwrap() { 'a'|'i'|'u'|'e'|'o' => pig.push_str("hay"), _ => { pig.push(s.chars().nth(0).unwrap()); pig.remove(0); pig.push_str("ay"); }, } pig }
nth()
関数がポイント。これまでのドキュメントには出てこなかった。ググって知った。
HashMap
問題。
ハッシュマップとベクタを使用して、ユーザに会社の部署に雇用者の名前を追加させられるテキストインターフェイスを作ってください。 例えば、"Add Sally to Engineering"(開発部門にサリーを追加)や"Add Amir to Sales"(販売部門にアミールを追加)などです。 それからユーザに、ある部署にいる人間の一覧や部署ごとにアルファベット順で並べ替えられた会社の全人間の一覧を扱わせてあげてください。
解答。
use std::collections::HashMap; use std::io::Write; fn main() { let mut employees: HashMap<String, Vec<String>> = HashMap::new(); loop { let mut s = String::new(); println!("コマンド: quit, add 部署名 従業員名, list [部署名]"); print!("> "); std::io::stdout().flush().unwrap(); std::io::stdin().read_line(&mut s).ok(); if !analize_command(&s.trim(), &mut employees) { break; } } } fn analize_command(s: &str, employees: &mut HashMap<String, Vec<String>>) -> bool { let commands: Vec<&str> = s.trim().split(' ').collect(); match commands[0] { "quit" => false, "add" if 2 < commands.len() => { add_employee(employees, commands[1], commands[2]); true }, "list" if 1 == commands.len() => { println!("{:?}", employees); true }, "list" if 1 < commands.len() => { println!("{:?}", employees.get(commands[1])); true }, _ => true, } } fn add_employee(employees: &mut HashMap<String, Vec<String>>, department: &str, employee: &str) { employees.entry(department.to_string()).or_insert(Vec::new()); employees.get_mut(department).unwrap().push(employee.to_string()); // https://users.rust-lang.org/t/hashmap-with-vector-values/17906 }
HashMapのget_mut()
関数がポイント。未学習。ググって知った。flush()
も同じ。
所感
問題を解くのは楽しかった。が、型名やAPIを知らないせいで、つまづきまくった。都度APIリファレンス等をググって何度も書いているうちに覚えるだろう。
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch 9.0 2018-11-13
- bash 4.4.12(1)-release
$ uname -a Linux raspberrypi 4.19.42-v7+ #1219 SMP Tue May 14 21:20:58 BST 2019 armv7l GNU/Linux
前回まで
- Rustを学んでみたい(プログラミング言語)
- Rustの環境構築
- RustでHelloWorld
- Rustの和訳ドキュメント
- Cargoでプロジェクト作成・ビルド・実行
- クレートとは?
- Rustで関数を使ってみる
- Rustでモジュールを使ってみる
- Rustで乱数を生成する(rand)
- Rustで標準入力する(std::io::stdin().read_line())
- RustでMatch判定する(match)
- Rustでprintとread_lineを1行にする方法
- Rustで数当てゲーム
- クレート名にドット.が使えない
- Rustの変数と可変性(let, mut) error[E0384]: cannot assign twice to immutable variable
x
- Rustのimmutable束縛とconst定数の違い
- RustのREPL、evcxrのインストールに失敗した
- Rustでコンパイルするときの変数未使用warningを消す
- Rustの変数(再代入、再宣言(シャドーイング))
- Rustのシャドーイングについて
- イミュータブルについて(副作用)
- Rustの定数(const)
- Rustのデータ型(数値)
- Rustのデータ型(論理)
- Rustのデータ型(文字)
- Rustのデータ型(タプル)
- Rustのデータ型(配列)
- Rustの関数
- Rustのif式
- Rustのくりかえし文(loop)
- Rustのくりかえし文(while)
- Rustのくりかえし文(for)
- Rustの所有権(ムーブ)
- Rustの所有権(関数)
- Rustの所有権(スライス)
- Rustの構造体(定義とインスタンス化)
- Rustの構造体(プログラム例)
- Rustの構造体(メソッド)
- Rustの列挙型(enum)
- Rustの列挙型(enum)
- Rustの列挙型(enum)
- Rustのmatch(制御フロー演算子)
- RustでNULLを扱う(Option, Some, None)
- NULL参照は10億ドルの失敗だった
- Rustの列挙型に独自表示を実装する(E0277 対策 std::fmt::Display 実装)
- RustのIfLet(matchの糖衣構文)
- Rustのプロジェクト構造
- Rustのcargoでライブラリ&テスト(単体、結合)
- Rustのモジュール(mod)
- Rustのモジュール(pub)
- Rustのmod参照方法(
mod 子モジュール名;
,use 要素名;
,extern crate クレート名;
,super
) - Rustのインポートまとめ(Rust2018)
- RustのコレクションVec型
- RustのコレクションString型
- RustのコレクションHashMap型