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

How do I output multiple values from .map() or use map twice in one iteration?

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

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, res_arr_from): (Vec<_>, 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<_>>();

参考:

摘录:

The map adapter is very useful, but only when the closure argument produces values. If it produces an iterator instead, there’s an extra layer of indirection. flat_map() will remove this extra layer on its own.

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

输出:

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

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

中的迭代器

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


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

输出:

Some(1)
Some(1)

peekable 的行为与其来源的迭代器相同,但添加了一些有趣的方法,如 .next_if(|x| x > 0),它会生成一个迭代器,该迭代器将继续呈现项目,直到条件计算为 false 而不消耗它没有呈现的最后一项。

最后一个主题符合“在一次迭代中使用 map 两次”,如果那样的话你可能意味着从 2 块的切片中提取项目。如果 v.result.transactions 本身就是一个 Vec,您可以使用 .chunks() 方法将其项目按 2 或 3 分组,如下所示:

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

输出:

[[1, 2, 3], [4, 5, 6], [7, 8, 9]]