Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

Rust辞典

  1. トップページ
  2. Rust辞典
  3. Iterator::enumerate() / zip() / flat_map()

Iterator::enumerate() / zip() / flat_map()

Rustのイテレータには、インデックス付きで列挙する『enumerate()』、2つのイテレータを組み合わせる『zip()』、ネストを平坦化しながら変換する『flat_map()』などがあります。

構文
// enumerate(): インデックスと要素のタプルを返します。
for (i, val) in vec!["a", "b", "c"].iter().enumerate() {
    println!("{}: {}", i, val);
}

// zip(): 2つのイテレータを組み合わせてタプルのイテレータにします。
let keys = vec!["a", "b", "c"];
let vals = vec![1, 2, 3];
let pairs: Vec<(_, _)> = keys.iter().zip(vals.iter()).collect();

// flat_map(): 変換してネストをフラット化します。
let words = vec!["hello world", "foo bar"];
let chars: Vec<&str> = words.iter().flat_map(|s| s.split_whitespace()).collect();

// flatten(): ネストしたイテレータを平坦化します。
let nested = vec![vec![1, 2], vec![3, 4], vec![5]];
let flat: Vec<i32> = nested.into_iter().flatten().collect();
メソッド一覧
メソッド概要
iter.enumerate()(index, value)のタプルを返すイテレータを生成します。
iter.zip(other)2つのイテレータを組み合わせて(a, b)のタプルを返します。
iter.flat_map(|x| ...)変換結果がイテレータの場合にフラット化します。
iter.flatten()ネストしたイテレータを一段階フラット化します。
iter.chain(other)2つのイテレータを連結して1つのイテレータにします。
iter.take(n)先頭からn個の要素だけを取り出します。
iter.skip(n)先頭n個の要素をスキップします。
iter.step_by(n)n個おきに要素を取り出します。
iter.rev()逆順にするイテレータを返します(DoubleEndedIteratorが必要)。
iter.peekable()次の要素を消費せずにpeek()で確認できるイテレータを返します。
サンプルコード
fn main() {
    // enumerate(): インデックス付きでループします。
    let fruits = vec!["apple", "banana", "cherry"];
    for (i, fruit) in fruits.iter().enumerate() {
        println!("{}: {}", i, fruit);
    }

    // enumerate() で番号付きリストを作ります。
    let numbered: Vec<String> = fruits.iter()
        .enumerate()
        .map(|(i, f)| format!("{}. {}", i + 1, f))
        .collect();
    println!("numbered: {:?}", numbered);

    // zip(): 2つのVecを組み合わせます。
    let names = vec!["Alice", "Bob", "Carol"];
    let scores = vec![90, 85, 92];
    let combined: Vec<(_, _)> = names.iter().zip(scores.iter()).collect();
    println!("zip: {:?}", combined);

    // zip() で HashMap を作ります。
    use std::collections::HashMap;
    let map: HashMap<_, _> = names.iter().zip(scores.iter()).collect();
    println!("zip to HashMap: {:?}", map);

    // flat_map(): 各文字列を単語に分割してフラット化します。
    let sentences = vec!["hello world", "foo bar baz"];
    let words: Vec<&str> = sentences.iter().flat_map(|s| s.split_whitespace()).collect();
    println!("flat_map words: {:?}", words);

    // flatten(): ネストしたVecを平坦化します。
    let nested = vec![vec![1, 2, 3], vec![4, 5], vec![6]];
    let flat: Vec<i32> = nested.into_iter().flatten().collect();
    println!("flatten: {:?}", flat);

    // chain(): 2つのイテレータを連結します。
    let a = vec![1, 2, 3];
    let b = vec![4, 5, 6];
    let chained: Vec<i32> = a.iter().chain(b.iter()).copied().collect();
    println!("chain: {:?}", chained);

    // take() と skip() です。
    let v: Vec<i32> = (1..=10).collect();
    let first3: Vec<_> = v.iter().take(3).collect();
    let skip3: Vec<_> = v.iter().skip(3).collect();
    println!("take(3): {:?}", first3);
    println!("skip(3): {:?}", skip3);
}
実行結果
0: apple
1: banana
2: cherry
numbered: ["1. apple", "2. banana", "3. cherry"]
zip: [("Alice", 90), ("Bob", 85), ("Carol", 92)]
zip to HashMap: {"Alice": 90, "Bob": 85, "Carol": 92}
flat_map words: ["hello", "world", "foo", "bar", "baz"]
flatten: [1, 2, 3, 4, 5, 6]
chain: [1, 2, 3, 4, 5, 6]
take(3): [1, 2, 3]
skip(3): [4, 5, 6, 7, 8, 9, 10]
概要

『zip()』は短い方のイテレータが尽きると終了します。長さが違う場合も安全に処理されます。両方の全要素を処理したい場合は『itertools』クレートの『zip_longest()』が使えます。

『flat_map()』は『map().flatten()』と同等です。ネストしたOptionやResultを処理するときにも便利です(例: 『iter.flat_map(|x| x.ok())』でエラーを無視して成功値だけ取り出せます)。

変換・絞り込みは『Iterator::map() / filter()』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。