我正在尝试压缩两个不等长的迭代器,仅当两个都有值时才返回,而忽略最长迭代器中的其余值。
fn main() {
let num1 = vec![1, 2];
let num2 = vec![3];
for i in num1.iter().rev().zip(num2.iter().rev()) {
println!("{:?}", i);
}
}
Run Code Online (Sandbox Code Playgroud)
这返回(2, 3)。我如何使它返回:
(2, 3)
(1, 0) // default is the 0 here.
Run Code Online (Sandbox Code Playgroud)
还有其他方法吗?
Pet*_*all 11
只要迭代器之一停止生成值,Zip 就会停止。如果你知道哪个是最长的,你可以用你的默认值填充较短的:
use std::iter;
fn main() {
let longer = vec![1, 2];
let shorter = vec![3];
for i in longer
.iter()
.rev()
.zip(shorter.iter().rev().chain(iter::repeat(&0)))
{
println!("{:?}", i);
}
}
Run Code Online (Sandbox Code Playgroud)
如果你不知道哪个最长,你应该使用 itertools,正如Peter Varo 建议的那样。
Pet*_*aro 10
您可以使用板条箱zip_longest提供的itertools。
use itertools::{
Itertools,
EitherOrBoth::*,
};
fn main() {
let num1 = vec![1, 2];
let num2 = vec![3];
for pair in num1.iter().rev().zip_longest(num2.iter().rev()) {
match pair {
Both(l, r) => println!("({:?}, {:?})", l, r),
Left(l) => println!("({:?}, 0)", l),
Right(r) => println!("(0, {:?})", r),
}
}
}
Run Code Online (Sandbox Code Playgroud)
这将产生以下输出:
(2, 3)
(1, 0)
Run Code Online (Sandbox Code Playgroud)
关键是要检测到一个迭代器比另一个迭代器短,在使用vector实现之前,您可以在做之前,ExactSizeIterator但是一般的解决方案是使用custom .zip()。
itertools已经提供了一个通用的解决方案.zip_longest():
use itertools::EitherOrBoth::{Both, Left, Right};
use itertools::Itertools;
fn main() {
let num1 = vec![1, 2];
let num2 = vec![3];
for i in num1
.iter()
.rev()
.zip_longest(num2.iter().rev())
.map(|x| match x {
Both(a, b) => (a, b),
Left(a) => (a, &0),
Right(b) => (&0, b),
})
{
println!("{:?}", i);
}
}
Run Code Online (Sandbox Code Playgroud)
这需要您每次都编写闭包,如果您需要此功能,则可能需要在.zip_default()其中带有where A和BImplement的迭代器上实现自定义特征Default:
use itertools::EitherOrBoth::{Both, Left, Right};
use itertools::Itertools;
fn main() {
let num1 = vec![1, 2];
let num2 = vec![3];
for i in num1
.iter()
.rev()
.zip_longest(num2.iter().rev())
.map(|x| match x {
Both(a, b) => (a, b),
Left(a) => (a, &0),
Right(b) => (&0, b),
})
{
println!("{:?}", i);
}
}
Run Code Online (Sandbox Code Playgroud)
使用itertools,我们可以委托一些逻辑:
use std::default::Default;
use std::iter::Fuse;
pub trait MyIterTools: Iterator {
fn zip_default<J>(self, other: J) -> ZipDefault<Self, J::IntoIter>
where
J: IntoIterator,
Self: Sized,
{
ZipDefault::new(self, other.into_iter())
}
}
#[derive(Clone, Debug)]
pub struct ZipDefault<I, J> {
i: Fuse<I>,
j: Fuse<J>,
}
impl<I, J> ZipDefault<I, J>
where
I: Iterator,
J: Iterator,
{
fn new(i: I, j: J) -> Self {
Self {
i: i.fuse(),
j: j.fuse(),
}
}
}
impl<T, U, A, B> Iterator for ZipDefault<T, U>
where
T: Iterator<Item = A>,
U: Iterator<Item = B>,
A: Default,
B: Default,
{
type Item = (A, B);
fn next(&mut self) -> Option<Self::Item> {
match (self.i.next(), self.j.next()) {
(Some(a), Some(b)) => Some((a, b)),
(Some(a), None) => Some((a, B::default())),
(None, Some(b)) => Some((A::default(), b)),
(None, None) => None,
}
}
}
impl<T: ?Sized> MyIterTools for T where T: Iterator {}
fn main() {
let num1 = vec![1, 2];
let num2 = vec![3];
for i in num1
.iter()
.copied()
.rev()
.zip_default(num2.iter().copied().rev())
{
println!("{:?}", i);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
126 次 |
| 最近记录: |