Rust中如何惯用且高效无重复遍历拆分向量为过滤结果及补集
Rust按过滤规则拆分Vector的最优实现
Rust标准库迭代器trait自带的partition方法就是专门适配这个场景的原生方案,同时满足单次遍历无额外性能开销、符合Rust惯用写法、无冗余样板代码三个要求,不需要手动写循环或者两次遍历。
基础用法(获取所有权拆分)
直接对原Vec的所有权迭代器调用partition,传入过滤闭包即可一次性得到符合条件的结果集和补集,性能和手写for循环完全一致,内部实现就是单次遍历、按判断结果分别推入两个目标集合:
let vct: Vec<u32> = vec![1, 3, 4, 7, 9, 10, 12]; let filter = |x: &u32| *x % 3 == 0; let (filtered, complement): (Vec<u32>, Vec<u32>) = vct.into_iter().partition(filter); println!("{:?}", filtered); // [3, 9, 12] println!("{:?}", complement); // [1, 4, 7, 10]
引用场景用法(不获取原数据所有权)
如果不需要拿走原Vec的所有权,只是需要拆分得到原元素的引用,也可以对不可变引用迭代器使用partition:
let vct: Vec<u32> = vec![1, 3, 4, 7, 9, 10, 12]; let filter = |x: &&u32| **x % 3 == 0; let (filtered_refs, complement_refs): (Vec<&u32>, Vec<&u32>) = vct.iter().partition(filter);
方案对比
- 和手写for循环相比:逻辑执行路径完全一致,性能没有差异,但是省去了手动声明可变Vec、手动写分支push的冗余样板代码,不需要暴露不必要的可变性。
- 和两次filter的朴素迭代器实现相比:只需要遍历一次原数组,没有重复遍历、重复克隆元素的额外开销,写法更简洁,闭包只需要定义一次不需要重复调用。
内容的提问来源于stack exchange,提问作者Luiz Martins
相关产品推荐
相关产品推荐

