rust - Rayon 折叠成一个 HashMap

标签 rust

我有一个 Vec<Result<MyStruct, ()>> ,我想将它们放入 HashMap 中的桶中,其中键是 MyStruct.b field 和 values 是一个包含所有 MyStructs 的 Vec MyStruct.b领域(见下面的 Playground 链接,可能更清楚)。我正在使用折叠,它适用于普通的 .fold

let my_array = vec![Ok(m1), Ok(m2), Ok(m3), Err(())];

let result: HashMap<String, Vec<&MyStruct>> = my_array
    .iter()
    .filter_map(|value| value.as_ref().ok())
    .fold(HashMap::new(), |mut acc, value| {
        acc.entry(value.b.clone()).or_insert(vec![]).push(&value);
        acc
    });

但是,我无法用人造丝实现同样的效果

let my_array = vec![Ok(m1), Ok(m2), Ok(m3), Err(())];

let result = my_array
    .par_iter()
    .filter_map(|value| value.as_ref().ok())
    .fold(
        ||HashMap::new(),
        |mut acc, value| {
            acc.entry(value.b.clone()).or_insert(vec![]).push(&value);
            acc
        }
    )
    .collect::<HashMap<String, Vec<&MyStruct>>>();

我得到的错误是

   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `std::collections::HashMap<std::string::String, std::vec::Vec<&MyStruct>>: rayon::iter::FromParallelIterator<std::collections::HashMap<std::string::String, std::vec::Vec<&&MyStruct>>>` is not satisfied
  --> src/main.rs:39:10
   |
39 |         .collect::<HashMap<String, Vec<&MyStruct>>>();
   |          ^^^^^^^ the trait `rayon::iter::FromParallelIterator<std::collections::HashMap<std::string::String, std::vec::Vec<&&MyStruct>>>` is not implemented for `std::collections::HashMap<std::string::String, std::vec::Vec<&MyStruct>>`
   |
   = help: the following implementations were found:
             <std::collections::HashMap<K, V, S> as rayon::iter::FromParallelIterator<(K, V)>>

Playground

最佳答案

根据 parallel fold documentation :

The parallel fold works similarly except that it first breaks up your list into sublists, and hence instead of yielding up a single sum at the end, it yields up multiple sums. The number of results is nondeterministic, as is the point where the breaks occur.

所以你想reducefold的结果变成一个值作为最终结果,而不是collect:

let result = my_array
    .par_iter()
    .filter_map(|value| value.as_ref().ok())
    .fold(
        || HashMap::new(),
        |mut acc, value| {
            acc.entry(value.b.clone()).or_insert(vec![]).push(value);
            acc
        },
    )
    .reduce(
        || HashMap::new(),
        |m1, m2| {
            m2.iter().fold(m1, |mut acc, (k, vs)| {
                acc.entry(k.clone()).or_insert(vec![]).extend(vs);
                acc
            })
        },
    );

OTOH :

reduce() requires that the identity function has the same type as the things you are iterating over, and it fully reduces the list of items into a single item

所以你可以一次性reduce到最终结果:

let result = my_array
    .par_iter()
    .filter_map(|value| value.as_ref().ok())
    .map(|s| {
        let mut m = HashMap::new();
        m.insert(s.b.clone(), vec![s]);
        m
    })
    .reduce(
        || HashMap::new(),
        |m1, m2| {
            m2.iter().fold(m1, |mut acc, (k, vs)| {
                acc.entry(k.clone()).or_insert(vec![]).extend(vs);
                acc
            })
        },
    );

选择fold or map/reduce由您决定。

关于rust - Rayon 折叠成一个 HashMap,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57641821/

相关文章:

rust - rust 中的 "const fn"可以连接字节切片吗?

types - 无法为字节切片实现更高等级的生命周期类型绑定(bind)

rust - 如何以独立于平台的方式使用leading_zeros/trailing_zeros?

rust - 为什么通过提取方法进行重构会触发借用检查器错误?

rust - 不同结构的实例作为函数的参数

reference - 可变引用生命周期与不可变引用生命周期

rust - 为什么 Godbolt 编译器资源管理器在 Release模式下编译时不显示我的函数的任何输出?

memory - 分配这个结构时,浪费了多少内存?

unit-testing - 运行时记录 `cargo test`

rust - 如何获得对RwLock内部对象的引用?