## はじめに [[std.result.Result]]を簡潔に作成するため以下の`result`関数を使う。 ```rust fn result<T, F>(x: T, isOk: F) -> Result<T, T> where T: Display, F: Fn(&T) -> bool, { if isOk(&x) { Ok(x) } else { Err(x) } } ``` > [!attention] > サンプルコードから[[itertools]]のuse文は省略する。 > [!caution] > 表現を簡略化するため、本来は[[iter()]]が使える箇所も[[into_iter()]]を使っているので、プロダクションコードでは適切な[[イテレータ]]に変換すること > [!info] > [[ユニットテスト]]ベースの関連コードは[[🦉rust-study]]を参照 ## 作成系 ### Vecの作成 [[vec!]]マクロを使う。 ```rust let xs = vec![10, 20, 30]; ``` #### 連続した数のVecを作成 ```rust let xs = (1..=5).collect::<Vec<_>>(); // [1, 2, 3, 4, 5] ``` #### 一定間隔ごとのVecを作成 ```rust let xs = (10..=50).step_by(10).collect::<Vec<_>>(); // [10, 20, 30, 40, 50] ``` ### Vecのクローン https://qiita.com/season3/items/90587883affc815a5cf9 ```rust let xs = vec![10, 20, 30]; let cloned = xs.iter().cloned(); // または // let cloned = xs.to_vec(); ``` ### rangeの作成 ```rust let range = 0..5; ``` ### index付きiteratorの作成 ```rust let indexed_iterator = vec!["aaa", "iii", "uuu"].iter().enumerate(); // [(0, "aaa"), (1, "iii"), (2, "uuu")] ``` ### 同じ値を繰り返すIteratorを作成 [[std.iter.fn.repeat]]を使う。 ```rust let endless_tadashi = iter::repeat("tadashi"); // 無限イテレータのため、数を制限する場合はtakeを使う endless_tadashi.take(3).collect_vec(); // ["tadashi", "tadashi", "tadashi"] ``` ### Vectorの結合 `Vec<T> -> Vec<T>` https://users.rust-lang.org/t/how-to-concatenate-two-vectors/8324/2 [[スライス (Rust)|スライス]]にしてから結合。 ```rust let seed1 = vec![10, 20, 30]; let seed2 = vec![40, 50]; // seed1[..] -> [i32] // &seed1[..] -> &[i32] // [&seed1[..], &seed2[..]] -> [&[i32]; 2] let actual = [&seed1[..], &seed2[..]].concat(); // [10, 20, 30, 40, 50] ``` [[ベクター]]のまま結合。 ```rust let mut seed = vec![10, 20, 30]; seed.extend(vec![40, 50]); // [10, 20, 30, 40, 50] ``` ## 変換系 ### [[スライス (Rust)|スライス]]をVecに変換 `&[T] -> Vec<T>` ```rust &[1, 2, 3].to_vec() // [1, 2, 3] ``` ### Vecを[[スライス (Rust)|スライス]]変換 `Vec<T> -> &[T]` ```rust let v = vec![1, 2, 3]; v.as_slice(); // &[1, 2, 3] &v[..]; // &[1, 2, 3] ``` ### IteratorをVecに変換 `Iter<T> -> Vec<T>` [[itertools.collect_vec]]を使う。 ```rust vec![10, 20, 30].into_iter().collect_vec(); // [10, 20, 30] ``` ### Vecの中身を実体化 `Vec<&T> -> Vec<T>` ```rust let s1 = &"aaa".to_string(); let s2 = &"bbb".to_string(); vec![s1, s2].into_iter().cloned().collect_vec(); // ["aaa", "bbb"] ``` ### 別の値に変換 `Vec<T> -> Vec<U>` [[std.iter.iterator.map]]を使う。 ```rust vec![10, 20, 30].iter().map(|x| x * 10).collect_vec(); // [100, 200, 300] ``` ### VecをOptionに変換 `Vec<T> -> Option<Vec<T>>` https://stackoverflow.com/questions/70546009/is-there-an-idiomatic-way-to-convert-empty-vec-to-none 空の場合はNoneにする。 ```rust pub fn vec_to_option<T>(vec: &Vec<T>) -> Option<Vec<T>> where T: Clone, { vec.is_empty().not().then_some(vec.to_vec()) } vec_to_option(vec!["a"]); // Some(["a"]) vec_to_option(vec![]); // None ``` ### インデクシング `Vec<T> -> HashMap<K, T>` collectで[[HashMap]]を指定する。 ```rust vec![10, 11, 22, 30] .into_iter() .map(|x| (x % 10, x)) .collect::<HashMap<_, _>>(); // {0: 30, 1: 11, 2: 22} ``` [[std.iter.iterator.fold]]を使うやり方もある。 ```rust vec![10, 11, 22, 30] .into_iter() .fold(HashMap::new(), |mut acc, c| { acc.insert(c % 10, c); acc }); // {0: 30, 1: 11, 2: 22} ``` ### グルーピング `Vec<T> -> HashMap<K, Vec<T>>` [[itertools.into_group_map_by]]を使う。 ```rust vec![10, 11, 22, 30] .into_iter() .into_group_map_by(|&x| x % 10); // {0: [10, 30], 1: [11], 2: [22]} ``` > [!attention] > [[Lodash]]に慣れていると[[itertools.group_by]]と勘違いしやすいので注意 ### グルーピングしてカウント `Vec<T> -> HashMap<K, usize>` [[itertools.counts_by]]を使う。 ```rust vec![10, 11, 22, 30].iter().counts_by(|&x| x % 10); // {0: 2, 1: 1, 2: 1} ``` ### OptionをResultに変換 `Option<T> -> Result<T, *>` [[Option.ok_or]]または[[Option.ok_or_else]]を使う。 ```rust let a = Some("some").ok_or("error"); // Ok("some") let a: Result<&str, &str> = None.ok_or("error"); // Err("error") ``` ### 複数のVecをzipしてVecに変換 `Vec<T1>, ..., Vec<Tn> -> Vec<U>` [[itertools.izip]]を使う。 ```ts let xs = vec!["a", "b", "c"]; let ys = vec!["A", "B", "C"]; let zs = vec![1, 2, 3]; izip!(&xs, &ys, &zs) .map(|(&a, &b, &c)| (a, b, c)) .collect_vec(); // [("a", "A", 1), ("b", "B", 2), ("c", "C", 3)] ``` ### 条件を満たす要素のVecと条件を満たさない要素のVecに分割 `Vec<T> -> (Vec<T>, Vec<T>)` [[itertools.partition]]を使う。 ```rust let (even, odd): (Vec<_>, Vec<_>) = vec![1, 2, 3, 4, 5] .into_iter() .partition(|&x| x % 2 == 0); // ([2, 4], [1, 3, 5]) ``` ### HashMapを値のVecに変換 `HashMap<K, T> -> Vec<T>` ```rust let map = hashmap! {101 => 1, 102 => 2, 103 => 3}; map.into_values().sorted().collect_vec(); // [1, 2, 3] ``` ## フィルタ系 ### 条件にあう要素のみフィルタ `Vec<T> -> Vec<T>` [[std.iter.iterator.filter]]を使う。 ```rust vec![10, 20, 30] .into_iter() .filter(|&x| x > 10) .collect_vec(); // [20, 30] ``` ### 有効値の中身のみをフィルタ `Vec<T> -> Vec<T>` [[std.iter.iterator.flatten]]を使う。 ```rust vec![Some(10), None, Some(30)] .into_iter() .flatten() .collect_vec(); // [10, 30] ``` ### 変換した結果が有効な要素のみを抽出 `Vec<T> -> Vec<T>` [[std.iter.iterator.flat_map]]を使う。 ```rust vec![10, 20, 30] .iter() .flat_map(|&x| result(x, |&v| v > 10)) .collect_vec(); // [20, 30] ``` ### 先頭の数要素を返す `Vec<T> -> Vec<T>` [[std.iter.iterator.take]]を使う。 ```rust vec![10, 20, 30, 40, 50] .into_iter() .take(3) .collect_vec(); // [10, 20, 30] ``` ### 先頭の数要素を取り除いた残りを返す `Vec<T> -> Vec<T>` [[std.iter.iterator.skip]]を使う。 ```rust vec![10, 20, 30, 40, 50] .into_iter() .skip(3) .collect_vec(); // [40, 50] ``` ### Vecの重複を削除(ユニーク) `Vec<T> -> Vec<T>` [[itertools.unique]]を使う。 ```rust vec![10, 20, 10, 30, 20].into_iter().unique().collect_vec(); // [10, 20, 30] ``` ミュータブルで要素がプリミティブ型の場合のみソートして`dedup`でもOK。 ```rust let mut xs = vec![10, 20, 10, 30, 20].into_iter().sorted().collect_vec(); xs.dedup(); xs // [10, 20, 30] ``` ### 条件を指定してVecの重複を削除(ユニーク) `Vec<T> -> Vec<T>` [[itertools.unique_by]]を使う。 ```rust vec![11, 22, 12, 31, 22] .into_iter() .unique_by(|&x| x % 10) // 1の位が同じものは重複とする .collect_vec(); // [11, 22] ``` ### VecをSetとして重複削除(ユニーク) `Vec<T> -> HashSet<T>` ```rust vec!["a", "b", "a", "c", "b", "a"] .into_iter() .collect::<HashSet<_>>(); // HashSet["a", "b", "c"] ``` ## ソート系 ### ソート `Vec<T> -> Vec<T>` [[itertools.sorted_by_key]]を使う。 ```rust vec![15, 23, 31, 42, 54] .into_iter() .sorted_by_key(|x| x % 10) // 1の位でソート .collect_vec(); // [31, 42, 23, 54, 15] ``` ### 浮動小数点型のソート `Vec<T> -> Vec<T>` 浮動小数点は[[Ordトレイト]]が実装されていないので、[[PartialOrdトレイト]]に実装されている`partial_cmp`を使う必要がある。 ```rust vec![1.0, 50.0, 15.0, 25.0, 30.0]; .into_iter() .sorted_by(|a, b| a.partial_cmp(b).unwrap()) .collect_vec(); // [1.0, 15.0, 25.0, 30.0, 50.0] ``` ### 並びを逆転 `Vec<T> -> Vec<T>` [[itertools.rev]]を使う。 ```rust vec![10, 20, 30].into_iter().rev().collect_vec(); // [30, 20, 10] ``` ## 抽出系 ### 条件にあう最初の要素を取得 `Vec<T> -> T` [[std.iter.iterator.find]]を使う。 ```rust vec![10, 20, 30].into_iter().find(|&x| x > 20) // Some(30) vec![10, 20, 30].into_iter().find(|&x| x > 30) // None ``` ### 最大値の取得 `Vec<T> -> T` [[std.iter.iterator.max]]を使う。 ```rust vec![30, 10, 20].into_iter().max(); // Some(30) ``` ### 最小値の取得 `Vec<T> -> T` [[std.iter.iterator.min]]を使う。 ```rust vec![30, 10, 20].into_iter().min(); // Some(10) ``` ### 変換結果が最大となる値の取得 `Vec<T> -> T` [[std.iter.iterator.max_by_key]]を使う。 ```rust vec![51, 43, 32].into_iter().max_by_key(|x| x % 10); // Some(43) ``` ### 変換結果が最小となる値の取得 `Vec<T> -> T` [[std.iter.iterator.min_by_key]]を使う。 ```rust vec![51, 43, 32].into_iter().min_by_key(|x| x % 10); // Some(51) ``` ## 畳み込み系 ### 初期値を指定して畳み込み `Vec<T> -> U` [[std.iter.iterator.fold]]を使う。 ```rust vec![10, 20, 30].into_iter().fold(100, |a, b| a - b); // 40 // -> 100 - 10 - 20 - 30 = 40 ``` ### 最初の要素を初期値として畳み込み `Vec<T> -> U` [[std.iter.iterator.reduce]]を使う。 ```rust vec![10, 20, 30].into_iter().reduce(|a, b| a - b); // Some(-40) // -> 10 - 20 - 30 = -40 ``` ## エラーハンドリング系 ### 変換に失敗した場合に最初に失敗した要素のエラーのみ返す `Vec<T> -> Result<Vec<T>, E>` ```rust vec![10, 20, 30, 40] .iter() .map(|&x| result(x, |&v| v < 30)) .collect::<Result<Vec<_>, _>>(); // Err(30) ``` > [!hint]- collectで`Result<Vec<_>, _>>`に変換が可能な理由 > ![[RustのcollectでItemのResultを複数ItemのResultに変換可能な理由]] ### 変換に失敗した場合に失敗した全要素のエラーを返す `Vec<T> -> Result<Vec<T>, Vec<E>>` [[itertools.partition_result]]を使って`Result<T, E>`を`(Vec<T>, Vec<E>)`に変換し、そのあとに[[パターンマッチ (Rust)|パターンマッチ]]で[[Result]]に変換する。 ```rust let ret: (Vec<_>, Vec<_>) = vec![10, 20, 30, 40] .iter() .map(|&x| result(x, |&v| v < 30)) .partition_result(); match ret { (oks, errs) if errs.is_empty() => Ok(oks), (_, errs) => Err(errs), } // Err([30, 40]) ``` #todo max #todo unwrap #todo unwrap_or ## Option ### 中身を実体化 `Option<&T> -> Option<T>` ```rust let s1 = &"aaa".to_string(); let seed = Some(s1); // Option<&String> seed.cloned(); // Option<String> ``` ### 中身をClone `Option<T> -> Option<T>` ```rust let s1 = Some("aaa".to_string()); let cloned = s1.as_ref().cloned().unwrap(); ``` ## 参考 - [Resultをイテレートする \- Rust By Example 日本語版](https://doc.rust-jp.rs/rust-by-example-ja/error/iter_result.html)