[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