如何迭代几个范围或迭代器的产品?

时间:2014-07-17 21:25:44

标签: iterator tuples rust

Rust中有一种自然的方法来迭代几个范围或迭代器的“产品”吗?

当您在多维数组或某些状态空间上进行迭代时,会出现这种情况。例如,我想考虑具有5个元素的布尔元组的所有可能值。嵌套5个for循环有点笨拙。

2 个答案:

答案 0 :(得分:9)

这是一个完成工作的宏:

#![feature(macro_rules)]

macro_rules! product(
    ($first:ident, $($next:ident),*) => (
        $first.iter() $(
            .flat_map(|e| std::iter::Repeat::new(e)
                .zip($next.iter()))
        )*
    );
)

fn main() {
    let a = ['A', 'B', 'C'];
    let b = [1i, 4];
    let c = [true, false];
    let d = ['x', 'y'];

    for (((a, b), c), d) in product![a, b, c, d] {
        println!("{} {} {} {}", a, b, c, d);
    }
}

输出:

A 1 true x
A 1 true y
A 1 false x
A 1 false y
A 4 true x
A 4 true y
etc...

Playpen example

宏扩展为以下

a.iter()
    .flat_map(|e| std::iter::Repeat::new(e).zip(b.iter()))
    .flat_map(|e| std::iter::Repeat::new(e).zip(c.iter()))
    .flat_map(|e| std::iter::Repeat::new(e).zip(d.iter()))

flat_map(|e| ... )将一系列迭代器组合到一个迭代器中。 e是迭代器产生的元素。

std::iter::Repeat::new(e)创建一个重复e

的迭代器

.zip( ... )同时迭代两个迭代器,产生两个元素作为一对。

宏的解释时间稍长,因此最好阅读macro guide

我不知道这是否是最好的方法。

答案 1 :(得分:6)

itertools crate有一个非常符合人体工程学的宏(iproduct!),用于迭代迭代器的乘积。这是一个例子:

#[macro_use]
extern crate itertools;

pub fn main() {
    let a = ['A', 'B', 'C'];
    let b = [1, 4];
    let c = [true, false];
    let d = ['x', 'y'];

    for (a, b, c, d) in iproduct!(&a, &b, &c, &d) {
        println!("{} {} {} {}", a, b, c, d);
    }
}