【问题标题】:How to iterate over the product of several ranges or iterators?如何迭代多个范围或迭代器的乘积?
【发布时间】:2014-09-08 22:20:39
【问题描述】:

Rust 中是否有一种自然的方式来迭代多个范围或迭代器的“乘积”?

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

【问题讨论】:

  • 我几乎认为我希望 bools 是一个特例,我想要一个不同的工具。但是对于其他情况,通用的会很方便。实际上,对于布尔值,许多人“迭代”(计数)std::bitset。
  • 在 Python 中你想要的是itertools.product。然而,在 Rust 中实现这样的事情并不像起初看起来那么容易。实现它通常需要宏。

标签: iterator tuples rust


【解决方案1】:

这是一个完成这项工作的宏:

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

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 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(e).zip(b.iter()))
    .flat_map(|e| std::iter::repeat(e).zip(c.iter()))
    .flat_map(|e| std::iter::repeat(e).zip(d.iter()))

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

std::iter::repeat(e) 创建一个重复 e 的迭代器。

.zip( ... ) 同时迭代两个迭代器,将两个迭代器的元素成对产生。

宏解释有点长,最好看macro chapter in the book

【讨论】:

  • 谢谢,您能简要介绍一下它的作用吗? (不是语法,只是基本技术。)我对 rust 非常陌生,想学习而不是复制/粘贴。 :)
  • 值得注意的是,这将为a的每个元素重新创建b迭代器,并为ab中的每对元素重新创建c迭代器,等等。所以如果这些中的任何一个都会消耗价值,或者很昂贵,或者应该只调用一次,那么这种策略不一定能按预期工作。 (但是,无论如何,实际上不可能生产出这样的迭代器,至少,如果没有首先收集到二级数据结构,比如Vec,我想大多数迭代器的制造成本都很便宜,所以这些似乎并不特别有问题。)
  • 代码需要修改才能在当前版本的rustc中工作,宏定义分隔符改为大括号,std::iter::Repeat::new改为std::iter::repeat,工作代码:play.rust-lang.org/…跨度>
【解决方案2】:

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

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 itertools::iproduct!(&a, &b, &c, &d) {
        println!("{} {} {} {}", a, b, c, d);
    }
}

【讨论】:

猜你喜欢
  • 2020-01-05
  • 1970-01-01
  • 2016-07-19
  • 2013-07-08
  • 2015-10-04
  • 2014-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多