[Rust] Iterator トレイトで自分がよく使うメソッドまとめ
一覧
| メソッド名 | 役割 |
|---|---|
| all | 全ての要素が条件を満たすかの確認 |
| any | 条件を満たす要素が1つでもあるかの確認 |
| cloned | イテレータの各要素をクローンして、新しいイテレータを作成する。 |
| collect | イテレータをコレクションに変換する |
| count | 要素数(ただし、イテレータを消費する) |
| filter | 条件を満たす要素のみで、新たにイテレータを作成する |
| filter_map | filterとmapの機能を組み合わせたもの |
| find | 条件を満たす最初の要素を返す |
| find_map | findとmapの機能を組み合わせたもの |
| map | 各要素にクロージャ適用して、新たにイテレータを作成する |
| position | 条件を満たす最初の要素のインデックスを返す |
| unzip | タプルのイテレータを2つの別々のコレクションに分割する |
| zip | 2つのイテレータの各要素ペア(タプル)として、1つの新たなイテレータを作成する |
🔸 all
各要素に対して、bool型を返すクロージャーを適用して、全ての要素で、trueになる場合は、trueを返す。
1つでもfalseになる要素がある場合は、falseを返す。
定義
fn all<F>(&mut self, f: F) -> bool
where
Self: Sized,
F: FnMut(Self::Item) -> bool,
例
let vec = vec![1, 2, 3, 4, 5];
println!("{}", vec.iter().all(|x| *x < 5)); // false
println!("{}", vec.iter().all(|x| *x < 10)); // true
🔸 any
各要素に対して、bool型を返すクロージャーを適用して、1つでもtrueになる要素がある場合は、trueを返す。
全ての要素でfalseになる場合は、falseを返す。
定義
fn any<F>(&mut self, f: F) -> bool
where
Self: Sized,
F: FnMut(Self::Item) -> bool,
例
let vec = vec![1, 2, 3, 4, 5];
println!("{}", vec.iter().any(|x| *x > 6)); // false
println!("{}", vec.iter().any(|x| *x >= 5)); // true
🔸 cloned
イテレータの各要素対してクローンを行なって、新しいイテレータを作成する。
また、&T(参照)のイテレータをT(値)のイテレータに変換する。
filterなど、要素数が変化するものに対しては、cloneの実行数を減らすために、可能な限り処理の最後にcloned()を配置するとパフォーマスが良くなる。
定義
fn cloned<'a, T>(self) -> Cloned<Self>
where
T: 'a + Clone,
Self: Sized + Iterator<Item = &'a T>,
例
let vec = vec![1,2,3,4,5];
let result: Vec<&i32> = vec.iter().collect();
println!("{:?}", result); // [1, 2, 3, 4, 5]
let result_cloned: Vec<i32> = vec.iter().cloned().collect();
println!("{:?}", result_cloned); // [1, 2, 3, 4, 5]
🔸 collect
イテレータをコレクションに変換する。
FromIteratorトレイトを実装している任意の型に変換できるため、以下のいずれかの方法で型を指定する必要がある。
-
- turbofish構文(::<>)を使用
-
- 変数の型注釈を使用
また、イテレータを消費する。
定義
fn collect<B>(self) -> B
where
B: FromIterator<Self::Item>,
Self: Sized,
例
let vec = vec![1, 2, 3, 4, 5];
let result_turbo_fish = vec.iter().map(|x| x + 1).collect::<Vec<i32>>();
let result_inference: Vec<i32> = vec.iter().map(|x| x + 1).collect();
println!("{:?}", result_turbo_fish);
println!("{:?}", result_inference);
🔸 count
Noneが見つかるまで、next関数を呼び出し続けて、見つかったSome数を返す(イテレータの要素数を返す)
ただし、イテレーターを消費する(consume)ため、呼び出し後は、イテレータを使用できなくなる。
定義
fn count(self) -> usize
where
Self: Sized,
例
let vec = vec![1, 2, 3, 4, 5];
println!("{}", vec.iter().count()); // 5
🔸 filter
各要素に対して、bool型を返すクロージャーを適用して、trueとなる要素から新たにイテレータを作成する。
クロージャーの引数は「参照」を受け取るため、参照の分配で「&」を使用して、参照を外すのが良い。
ただし、遅延評価のため、実際にイタレータが消費されるまで、計算が行われない。
定義
fn filter<P>(self, predicate: P) -> Filter<Self, P>
where
Self: Sized,
P: FnMut(&Self::Item) -> bool,
例
let vec = vec![1, 2, 3, 4, 5];
let result_iter = vec.iter().filter(|&x| x % 2 == 0);
println!(" {:?}", result_iter); // Filter { iter: Iter([1, 2, 3, 4, 5]) }
// collectにより、vecに変換して、イタレータが消費されて、filterのクロージャーの処理が行われる。
let result_vec = result_iter.collect::<Vec<&i32>>();
println!(" {:?}", result_vec); // [2, 4]
🔸 filter_map
各要素に、Optionを返すクロージャーを適用し、Someを返す要素のみで、新たにイテレータを作成する。
filterとmapの機能を組み合わせたもの。
定義
fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
where
Self: Sized,
F: FnMut(Self::Item) -> Option<B>,
例
filter_map
// 偶数のみを取り出して3倍する
let vec = vec![1, 2, 3, 4, 5];
let result = vec.iter().filter_map(|&x| {
if x % 2 == 0 {
Some(x * 3)
} else {
None
}
});
println!("{:?}", result.collect::<Vec<i32>>()); // [6, 12]
filter + map
let vec = vec![1, 2, 3, 4, 5];
let result = vec.iter().filter(|&x| x % 2 == 0).map(|x| x * 3);
println!("{:?}", result.collect::<Vec<i32>>()); // [6, 12]
🔸 find
各要素に対して、bool型を返すクロージャーを適用して、trueとなる最初の要素をSome(elment)として返す。
全ての要素でfalseになる場合は、Noneを返す。
filterと同じく、クロージャーの引数は「参照」を受け取るため、参照の分配で「&」を使用して、参照を外すのが良い。
定義
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where
Self: Sized,
P: FnMut(&Self::Item) -> bool,
例
let vec = vec![1, 2, 3, 4, 5];
let result_some = vec.iter().find(|&x| x * 3 > 10);
println!(" {:?}", result_some.unwrap()); // 4
let result_none = vec.iter().find(|&x| x % 10 == 0);
println!(" {:?}", result_none); // None
🔸 find_map
各要素に、Optionを返すクロージャーを適用し、最初にSomeを返す要素を返す。
findとmapの機能を組み合わせたもの。
定義
fn find_map<B, F>(&mut self, f: F) -> Option<B>
where
Self: Sized,
F: FnMut(Self::Item) -> Option<B>,
例
find_map
let vec = vec![1, 2, 3, 4, 5];
let result_some = vec.iter().find_map(|&x| if x % 2 == 0 { Some(x * 3) } else { None });
println!(" {:?}", result_some.unwrap()); // 6
let result_none = vec.iter().find_map(|&x| if x % 10 == 0 { Some(x * 3) } else { None });
println!(" {:?}", result_none); // None
find + map
let vec = vec![1, 2, 3, 4, 5];
let result_find_map_some = vec.iter().find(|&x| x % 2 == 0).map(|&x| x * 3);
println!(" {:?}", result_find_map_some.unwrap()); // 6
let result_find_map_none = vec.iter().find(|&x| x % 10 == 0).map(|&x| x * 3);
println!(" {:?}", result_find_map_none); // None
🔸 map
各要素にクロージャーを適用し、クロージャーの返り値から、新たにイテレータを作成する。
ただし、遅延評価のため、実際にイタレータが消費されるまで、計算が行われない。
例
let vec = vec![1, 2, 3, 4, 5];
// 中身を表示しているだけのため、mapのクロージャーの処理はまだ行われていない
let result_iter= vec.iter().map(|x| x * 2);
println!(" {:?}", result_iter); // Map { iter: Iter([1, 2, 3, 4, 5]) }
// collectにより、vecに変換して、イタレータが消費されて、mapのクロージャーの処理が行われる。
let result_vec = result_iter.collect::<Vec<i32>>();
println!(" {:?}", result_vec); // [2, 4, 6, 8, 10]
🔸 position
各要素に対して、bool型を返すクロージャーを適用して、trueとなる最初の要素のインデックスをSome(i)として返す。
trueとなる要素が1つもない場合は、Noneを返す。
定義
fn position<P>(&mut self, predicate: P) -> Option<usize>
where
Self: Sized,
P: FnMut(Self::Item) -> bool,
例
let vec = vec![1, 2, 3, 4, 5];
let result_some = vec.iter().position(|&x| x == 3);
println!(" {:?}", result_some.unwrap()); // 2
let result_none = vec.iter().position(|&x| x % 10 == 0);
println!(" {:?}", result_none); // None
🔸 unzip
タプルのイテレータを2つの別々のコレクションに分割する。
左側の要素と右側の要素のそれぞれでコレクションが作成される。
定義
fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB)
where
FromA: Default + Extend<A>,
FromB: Default + Extend<B>,
Self: Sized + Iterator<Item = (A, B)>,
例
let vec = vec![(1, "a"), (2, "b"), (3, "c"), (4, "d"), (5, "e")];
let (result_left, result_right): (Vec<i32>, Vec<&str>) = vec.iter().cloned().unzip();
println!("{:?}", result_left); // [1, 2, 3, 4, 5]
println!("{:?}", result_right); // ["a", "b", "c", "d", "e"]
🔸 zip
2つのイテレータの要素を組み合わせて、新しいイテレータを作成する。
各要素は(a, b)の形式のタプルとして返される。
短い方のイテレータの長さに合わせて処理が終了する。
(0..)で無限イテレータを作成し、zipと組み合わせることで、インデックス付きのイテレーションを作成できる。
定義
fn zip<U>(self, other: U) -> Zip<Self, <U as IntoIterator>::IntoIter>
where
Self: Sized,
U: IntoIterator,
例
let vec = vec![1, 2, 3, 4, 5];
let vec2 = vec![6, 7, 8, 9];
let result_zip = vec.iter().zip(vec2.iter());
// a: 1, b:6
// a: 2, b:7
// a: 3, b:8
// a: 4, b:9
for (a, b) in result_zip {
println!("a: {}, b:{}", a, b);
}
let result_index = (0..).zip(vec2.iter());
// a: 0, b:6
// a: 1, b:7
// a: 2, b:8
// a: 3, b:9
// a: 4, b:10
for (a, b) in result_index {
println!("a: {}, b:{}", a, b);
}
typescriptとの比較表
自分がよくTypeScriptを使用するため、その比較表
| Rust | TypeScript |
|---|---|
all |
every |
any |
some |
cloned |
slice/map/[...array](スプレッド構文)など |
collect |
Array.from |
count |
length |
filter |
filter |
filter_map |
filter+map
|
find |
find |
find_map |
find+map
|
map |
map |
position |
findIndex |
unzip |
- |
zip |
- |
参考
Discussion