如何从 .map() 输出多个值或在一次迭代中使用 map 两次?

问题描述

如何在一个 into_iter 上使用 map 两次。目前我有

let res_arr_to: Vec<String> = v.result.transactions.into_iter().map( |x| x.to).collect();
let res_arr_from: Vec<String> = v.result.transactions.into_iter().map( |x| x.from).collect();

我想要的是一个数组中的两个数组,顺序无关紧要。我需要一个输出两个值的闭包(如果那是一个闭包?)。或者在一次迭代中使用 map 两次的方法,而不使用生成的值,而是在有意义且可能的情况下使用未触及的迭代器。我对函数式编程完全是个菜鸟,所以如果有一种完全不同的方法来做到这一点,另一种解释是可以的。

v 是一个 EthBlockTxResponse:

#[derive(Debug,Deserialize)]
struct EthTransactionObj {
    from: String,to: String

}

#[derive(Debug,Deserialize)]
struct EthTransactions {
    transactions : Vec<EthTransactionObj>
}

#[derive(Debug,Deserialize)]
struct EthBlockTxResponse {
    result : EthTransactions
}

谢谢

解决方法

您可以像这样使用 .unzip() 一次收集两个向量:

let (res_arr_to,res_arr_from): (Vec<_>,Vec<_>) = 
    v.result.transactions.into_iter().map(|x| (x.to,x.from)).unzip();

请注意 into_iter 消耗 v.result.transactions - 移出该字段。这可能不是您想要的,在这种情况下您应该复制字符串:

let (res_arr_to,Vec<_>) = 
    v.result.transactions.iter().map(|x| (x.to.clone(),x.from.clone())).unzip();
,

我觉得这个问题有点含糊,但认为您正在尝试同时获取 x.tox.from,而不是必须迭代数据两次并构建两个向量。我会先解决这个问题,然后再谈谈你提到的其他一些事情可能意味着什么。

一种方法是使用 .flat_map()。这将产生一个平面向量,去除额外的嵌套层次。如果你想要元组,你可以使用 .map(|x| (x.from,x.to))。我假设 x.fromx.toCopy 并且您实际上希望所有内容都在单个向量中而无需嵌套。

let res_arr_combined = v.result.transactions.into_iter()
                                            .flat_map( |x| [x.to,x.from])
                                            .collect::<Vec<_>>();

参考:

摘录:

地图适配器非常有用,但仅当闭包参数产生值时才有用。如果它产生一个迭代器,就会有一个额外的间接层。 flat_map() 会自行删除这个额外的图层。

fn main()
{
    // Adding more data to an iterator stream.
    (0..5).flat_map(|n| [n,n * n])
          .for_each(|n| print!("{},",n));
                  
    println!("");
}

输出:

0,1,2,4,3,9,16,

您可能并不真正需要以下内容,但是写下您希望在不使用值或更改迭代器状态的情况下从迭代器获取数据的评论,您可以对包装的迭代器调用 .peek() 操作在Peekable

要获得可查看的迭代器,您只需在任何迭代器上调用 .peekable()


    let mut p = [1,4].into_iter().peekable();
    
    println!("{:?}",p.peek());
    println!("{:?}",p.next());

输出:

Some(1)
Some(1)

peekable 的行为方式与它取自的迭代器相同,但添加了一些有趣的方法,如 .next_if(|x| x > 0),它生成一个迭代器,它将继续渲染项目,直到条件评估为 false 而不消耗最后一个项目它没有呈现。

最后一个主题与“在一次迭代中使用两次地图”相一致,如果通过这种方式您可能想从切片中以 2 块为单位提取项目。如果 v.result.transactions 本身就是一个 Vec ,您可以使用 .chunks() 方法将其项目按 2 或 3 分组,如下所示:

    let a = [1,5,6,7,8,9].chunks(3).collect::<Vec<_>>();    
    println!("{:?}",a);

输出:

[[1,3],[4,6],[7,9]]