我有一个 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)>>
最佳答案
根据 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.
所以你想reduce
将fold
的结果变成一个值作为最终结果,而不是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/