如何在Rust迭代器中每隔n个元素插入指定值?
每隔N个字符插入换行符的实现方案
针对你提出的字符迭代器需求,这里提供几种可行的实现方式:
标准库原生实现
不需要依赖第三方库,我们可以用Iterator::scan跟踪当前已处理的字符数量,每处理完N个字符后插入换行符,同时避免在字符串末尾额外添加换行:
let iter = "abcdefghijklmnopqrstuvwxyz".chars(); let n = 10; let iter_with_newlines = iter.scan(0, |count, c| { let mut res = vec![c]; *count += 1; if *count % n == 0 { res.push('\n'); } Some(res.into_iter()) }).flatten(); let string: String = iter_with_newlines.collect(); assert_eq!("abcdefghij\nklmnopqrst\nuvwxyz", string);
原理说明:
scan方法携带一个计数器状态,每处理一个字符就递增计数- 当计数达到N的倍数时,在当前字符后追加换行符
- 最后通过
flatten把嵌套的迭代器展开成单个字符迭代器
借助itertools库实现(匹配你的思路)
如果你希望用类似chunks + intersperse的方式实现,可以使用itertools crate,它给Iterator提供了chunks方法,正好符合你最初的设想:
首先在Cargo.toml中添加依赖:
[dependencies] itertools = "0.12"
然后实现代码:
use itertools::{Itertools, intersperse}; let iter = "abcdefghijklmnopqrstuvwxyz".chars(); let n = 10; let iter_with_newlines = iter.chunks(n).into_iter() .intersperse(std::iter::once('\n')) .flatten(); let string: String = iter_with_newlines.collect(); assert_eq!("abcdefghij\nklmnopqrst\nuvwxyz", string);
原理说明:
chunks(n)把原字符迭代器分割成多个长度为n的子迭代器(最后一个可能不足n)intersperse在每个子迭代器之间插入包含换行符的迭代器flatten将所有子迭代器和插入的换行符展开成连续的字符流
自定义迭代器适配器(进阶)
如果你想要一个通用的intersperse_every方法,可以自己实现一个迭代器适配器:
struct IntersperseEvery<I, T> { iter: I, n: usize, count: usize, separator: T, pending_sep: bool, } impl<I, T> IntersperseEvery<I, T> where I: Iterator<Item = T>, T: Clone, { fn new(iter: I, n: usize, separator: T) -> Self { Self { iter, n, count: 0, separator, pending_sep: false, } } } impl<I, T> Iterator for IntersperseEvery<I, T> where I: Iterator<Item = T>, T: Clone, { type Item = T; fn next(&mut self) -> Option<Self::Item> { if self.pending_sep { self.pending_sep = false; return Some(self.separator.clone()); } match self.iter.next() { Some(item) => { self.count += 1; if self.count % self.n == 0 { self.pending_sep = true; } Some(item) } None => None, } } } // 给Iterator添加扩展方法 trait IntersperseEveryExt: Iterator { fn intersperse_every(self, n: usize, separator: Self::Item) -> IntersperseEvery<Self, Self::Item> where Self::Item: Clone, Self: Sized, { IntersperseEvery::new(self, n, separator) } } impl<I: Iterator> IntersperseEveryExt for I {} // 使用示例 let iter = "abcdefghijklmnopqrstuvwxyz".chars(); let iter_with_newlines = iter.intersperse_every(10, '\n'); let string: String = iter_with_newlines.collect(); assert_eq!("abcdefghij\nklmnopqrst\nuvwxyz", string);
这个适配器会在每处理完N个元素后插入指定的分隔符,完全匹配你设想的intersperseEvery方法的功能。
内容的提问来源于stack exchange,提问作者baNaNa
相关产品推荐
相关产品推荐

