【问题标题】:Creating a HashMap in Rust using the fold iterator method使用折叠迭代器方法在 Rust 中创建 HashMap
【发布时间】:2022-01-20 19:26:17
【问题描述】:

我正在尝试使用 Entry 和 Rust 中的迭代器从单词数组中创建字数 HashMap。当我尝试如下时,

use std::collections::HashMap;
fn main () {
    let corpus = ["foo", "bar", "bar", "grok", "blah", "foo", "bar"];
    let mut word_count = corpus.iter().fold(HashMap::new(), |mut acc, word| *acc.entry(word).or_insert(0) += 1);
    println!("{:?}", word_count);
}

我收到错误:预期结构 HashMap,找到 (),类型不匹配

我可以通过创建一个新范围并将累加器显式返回为:

use std::collections::HashMap;
fn main () {
    let corpus = ["foo", "bar", "bar", "grok", "blah", "foo", "bar"];
    let mut word_count = corpus.iter().fold(HashMap::new(), |mut acc, word|{
        *acc.entry(word).or_insert(0) += 1;
        acc
    });
    println!("{:?}", word_count);
}

我得到了预期的{"foo": 2, "bar": 3, "blah": 1, "grok": 1}

通常fold 返回累加器的最后状态,所以我期待第一种方法可以工作,但不清楚为什么它不工作。非常感谢您对替代方法(使用迭代器)进行一些澄清和任何建议。

【问题讨论】:

  • 传入 fold 的闭包是 FnMut(B, Self::Item) -> B 类型的,这意味着累加器被移动到闭包范围内(而不是作为可变引用传入),并且闭包应该返回修改后的蓄能器。表达式*acc.entry(word).or_insert(0) += 1 的类型是单元类型(),因此编译器正确地将其标记为错误。
  • 啊,我明白了。我是否理解正确,因为*acc.entry(word).or_insert(0) += 1 是一个语句,在第一种情况下,闭包实际上并没有返回任何东西,而它应该像在第二种情况下一样返回修改后的累加器?
  • @Py_Dream 从技术上讲,这是一个返回 () 的表达式,但您可以将其视为一个语句。

标签: rust hashmap iterator


【解决方案1】:

就像@PitaJ 的评论中解释的那样,*acc.entry(word).or_insert(0) += 1 的类型为(),而编译器期望fold() 的回调每次都返回下一个状态(在其他语言中有时称为reduce(),例如 JavaScript; 在 Rust 中;fold() 允许您指定起始值,而 reduce() 从迭代器中的第一项获取它。

因此,我觉得循环更适合用例,因为您不需要返回新状态而是更新地图:

let mut word_count = HashMap::new();
for word in &corpus {
    *word_count.entry(word).or_insert(0) += 1;
}

Playground.

但是,如果您愿意,itertools crate 中有一个方法可以做到这一点:counts():

let word_count = corpus.iter().counts();

Playground.

【讨论】:

  • 感谢您的回复和您提出的替代方案!我更喜欢迭代器的原因是它更容易与人造丝并行化。您是否碰巧知道 itertools 方法是否可以对来自 rayon 的并行迭代器进行操作?
  • @Py_Dream 不幸的是,他们没有。虽然如果你想并行化它,你可能也需要替换映射:HashMap 不允许你共享突变(entry() 需要&mut self),并且使用互斥锁可能比顺序执行更值得。您可以使用 dashmap crate 中的 DashMap
  • 哦,太好了!没有考虑到。非常感谢您的想法。
猜你喜欢
  • 1970-01-01
  • 2015-01-07
  • 2020-10-26
  • 2011-07-09
  • 1970-01-01
  • 2020-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多