如何在Rust中实现take_n_saving,保留指定数量非空行及中间空行
Rust实现提取指定数量非空行并保留中间空行
针对你的需求,我们可以通过两种方式实现:一种是用fold快速处理,另一种是自定义迭代器适配器实现你想要的take_n_saving链式调用风格。
方法一:使用fold直接处理
这种方式无需额外定义结构体,适合快速实现需求:
let lines = vec![ "import a\n", "\n", "\n", "b = 1 + 2\n", "\n", "print(b)\n", "print(b + 1)\n", "\n", ]; // 用fold迭代收集,同时跟踪非空行的数量 let (result, _) = lines.into_iter().fold( (Vec::new(), 0), |(mut acc, count), line| { // 已经收集够3个非空行,直接返回当前结果 if count >= 3 { return (acc, count); } acc.push(line); // 如果当前行不是空行,计数加1 let new_count = if line != "\n" { count + 1 } else { count }; (acc, new_count) }, ); // 此时result就是你想要的结果
方法二:自定义迭代器适配器实现take_n_saving
如果你希望用链式调用的方式实现类似take_n_saving的功能,可以自定义一个迭代器扩展:
首先定义迭代器结构体和扩展 trait:
struct TakeNSaving<I, F> { iter: I, predicate: F, target_count: usize, current_count: usize, } // 实现Iterator trait impl<I, F, T> Iterator for TakeNSaving<I, F> where I: Iterator<Item = T>, F: Fn(&T) -> bool, T: Clone, { type Item = T; fn next(&mut self) -> Option<Self::Item> { // 已收集够目标数量,停止迭代 if self.current_count >= self.target_count { return None; } self.iter.next().map(|item| { // 如果当前行不满足谓词(即不是空行),计数加1 if !(self.predicate)(&item) { self.current_count += 1; } item }) } } // 定义扩展trait,让所有迭代器都能调用take_n_saving trait TakeNSavingExt: Iterator { fn take_n_saving<F>(self, target_count: usize, predicate: F) -> TakeNSaving<Self, F> where Self: Sized, F: Fn(&Self::Item) -> bool, { TakeNSaving { iter: self, predicate, target_count, current_count: 0, } } } // 为所有Iterator实现这个扩展 impl<I: Iterator> TakeNSavingExt for I {}
然后就可以像你期望的那样链式调用了:
let lines = vec![ "import a\n", "\n", "\n", "b = 1 + 2\n", "\n", "print(b)\n", "print(b + 1)\n", "\n", ]; let result: Vec<_> = lines.into_iter() .take_n_saving(3, |line| line == "\n") .collect(); // result即为预期的向量
说明
take_n_saving的第一个参数是需要提取的目标行数量(这里是3),第二个参数是不需要计数但需要保留的行的判断谓词(这里是判断是否为"\n")。- 迭代过程中,会一直收集行,直到收集够指定数量的非谓词匹配行,之后停止迭代,完美保留中间的空行。
内容的提问来源于stack exchange,提问作者Max Smirnov
相关产品推荐
相关产品推荐

