在Python中,我可以做到:
from itertools import product
k = 3
for kmer in product("AGTC", repeat=k):
print(kmer)
在 Rust 中,我可以通过以下方式强制k=3
的行为:
#[macro_use] extern crate itertools;
for kmer in iproduct!("AGTC".chars(), "AGTC".chars(), "AGTC".chars()){
println!("{:?}", kmer);
}
但是,如果我想要k=4
或k=5
呢?
任何 k 编写任何类型的正确泛化都很难,因为返回类型可以是任何大小的元组。由于您只想在String
上工作,因此很容易: 游乐场
fn kproduct(seq: String, k: u32) -> Vec<String> {
match k {
0 => vec![],
1 => seq.chars().map(|c| c.to_string()).collect(),
2 => iproduct!(seq.chars(), seq.chars()).map(|(a, b)| format!("{}{}", a, b)).collect(),
_ => iproduct!(kproduct(seq.clone(), k - 1), seq.chars()).map(|(a, b)| format!("{}{}", a, b)).collect(),
}
}
我在 4 年后回答这个问题,因为接受的答案太复杂了,而且因为 Python 的itertools.product
是一个通用函数(而接受的答案仅适用于 String
s(。此外,请注意,在接受的答案中定义的kproduct
函数是递归的,并且 Rust 不保证尾调用优化。
使用第三方 itertools crate,我们可以通过两种方式定义product_repeat
函数:要么通过定义一个标准的顶级函数,要么为所有Iterator
添加一个ProductRepeat
特征。
这是顶级函数:
use itertools::{Itertools, MultiProduct};
/// Rust version of Python's itertools.product().
/// It returns the cartesian product of the input iterables, and it is
/// semantically equivalent to `repeat` nested for loops.
///
/// # Arguments
///
/// * `it` - An iterator over a cloneable data structure
/// * `repeat` - Number of repetitions of the given iterator
pub fn product_repeat<I>(it: I, repeat: usize) -> MultiProduct<I>
where
I: Iterator + Clone,
I::Item: Clone {
std::iter::repeat(it)
.take(repeat)
.multi_cartesian_product()
}
如果您更喜欢增强迭代器特征,则可以执行以下操作:
pub trait ProductRepeat: Iterator + Clone
where Self::Item: Clone {
fn product_repeat(self, repeat: usize) -> MultiProduct<Self> {
std::iter::repeat(self)
.take(repeat)
.multi_cartesian_product()
}
}
impl<T: Iterator + Clone> ProductRepeat for T
where T::Item: Clone {}
这是 Rust 操场上的一个演示。