获得向量过滤器及其补集的习惯而有效的方法



假设我有一个向量,上面有一个过滤器,我想把它分解成两个向量:一个过滤的向量,和它的补。我认为有两种方法。第一个是for循环:

let vct: Vec<u32> = vec![1, 3, 4, 7, 9, 10, 12];
let filter = |x| x % 3 == 0;
let mut filtered: Vec<u32> = Vec::new();
let mut complement: Vec<u32> = Vec::new();
for v in vct {
if filter(v) {
filtered.push(v);
} else {
complement.push(v);
}
}
println!("{:?}", filtered);   //[3, 9, 12]
println!("{:?}", complement); //[1, 4, 7, 10]

这看起来很有效,但是不必要的冗长(并且给vector增加了不必要的可变性)。另一种是使用迭代器的朴素方法:

let vct: Vec<u32> = vec![1, 3, 4, 7, 9, 10, 12];
let filter = |x:&&u32| *x % 3 == 0;
let filtered: Vec<u32> = vct.iter().filter(filter).cloned().collect();
let complement: Vec<u32> = vct.into_iter().filter(|x| !filter(&x)).collect();
println!("{:?}", filtered);   //[3, 9, 12]
println!("{:?}", complement); //[1, 4, 7, 10]

具有更清晰的意图和更少的冗长(保存filter的定义/用法,它有点难看),但是在数组上迭代两次,这似乎是不必要的。

这两个解决方案似乎都不是最优的。

是否有一种惯用的有效的方法(不需要重复迭代)将向量拆分为过滤器和它的补集?

您尝试执行的操作称为分区。你可以使用Iterator.partition():

let vct: Vec<u32> = vec![1, 3, 4, 7, 9, 10, 12];
let filter: fn(u32) -> bool = |x| x % 3 == 0;
let (filtered, complement): (Vec<u32>, Vec<u32>) = vct.iter().partition(|x| filter(**x));
assert_eq!(&[3, 9, 12], filtered.as_slice());
assert_eq!(&[1, 4, 7, 10], complement.as_slice());

游乐场

最新更新