【问题标题】:Rust: simple simultaneous iteration of two hashmaps without zippingRust:两个哈希图的简单同时迭代,无需压缩
【发布时间】:2021-03-14 10:53:39
【问题描述】:

我正在尝试使用一个键同时循环两个地图,而不调用 zip()。 我似乎无法让以下代码工作。我做错了什么?

main.rs

use std::collections::HashMap;

mod iteratemaps;

fn main() {
    let mut m1 = HashMap::new();
    m1.insert(0, 10);
    m1.insert(1, 11);
    m1.insert(2, 12);

    let mut m2 = HashMap::new();
    m2.insert(0, 20);
    m2.insert(1, 21);
    m2.insert(2, 22);

    iteratemaps::iterate_maps(&m1, &m2);
}

iteratemaps.rs

use std::collections::HashMap;

pub fn iterate_maps(
    m1: &HashMap<u32, i32>,
    m2: &HashMap<u32, i32>,
) {
    // doesn't work
    for i in 0..m1.len() {
        println!("{:?}, {:?}", m1.get(&i), m2.get(&i));
    }

    // works
    // for (k, e1) in m1.iter() {
    //     let mut e2 = m2.get(k);
    //     println!("{:?}, {:?}", e1, e2)
    // }
}

我得到的错误是:

9 |         println!("{:?}, {:?}", m1.get(&i), m2.get(&i));
  |                                       ^^ expected `u32`, found `usize

【问题讨论】:

  • 好吧,m1.len() 返回一个usize,而您的密钥是u32。一个需要明确地转换为另一个。也就是说,如果你的键总是像这样连续,那么 Vec 理论上不会比 HashMap 更好吗?
  • 是的,我知道我需要转换为 u32,我似乎没有正确理解语法。那会怎么样?是的,一个 Vec 是有意义的,但这是一个最小的例子。我这里需要一个 HashMap。
  • i as u32 应该可以工作。请注意,如果i 大于u32 可以容纳的大小,这种原始类型转换会静默溢出。
  • 你不能使用zip的原因是什么?
  • 因为我想用同一个key依次遍历两张map。我想做一个结果[i] = m1[i] * m2[i]。也许我做错了什么,但无法使用 zip 从 m1 和 m2 地图中获取相同的索引。

标签: rust


【解决方案1】:

您可以将 i 转换为 u32,如 cmets 中所述,但更可靠的解决方案是仅迭代其中一个哈希映射的 。这不仅具有自动提供正确类型的优点(它甚至是一个引用,这是您需要传递给HashMap::get 的内容),而且即使您远离连续的整数键,它也可以工作。例如:

pub fn iterate_maps(m1: &HashMap<u32, i32>, m2: &HashMap<u32, i32>) {
    for k in m1.keys() {
        println!("{:?}, {:?}", m1.get(k), m2.get(k));
    }
}

您可以通过遍历第一个 hashmap 的键和值来避免不必要的哈希表查找,并且只查找第二个中的键:

pub fn iterate_maps(m1: &HashMap<u32, i32>, m2: &HashMap<u32, i32>) {
    for (k, v1) in m1 {
        let v2 = m2.get(k);
        println!("{:?}, {:?}", v1, v2);
    }
}

在处理此代码时,我想到了一个额外的改进:它可以在两个哈希图中的键和值上返回一个 迭代器,以便调用者决定如何使用这些值。 (您可以将迭代器视为zip 的变体,它实际上适用于您的用例。)同时,我们可以使函数在键和值类型上通用,以便它适用于任何类型的哈希图.结果如下所示:

pub fn iterate_maps<'a: 'b, 'b, K: Eq + Hash, V>(
    m1: &'a HashMap<K, V>,
    m2: &'b HashMap<K, V>,
) -> impl Iterator<Item = (&'a K, &'a V, &'b V)> {
    m1.iter().map(move |(k, v1)| (k, v1, m2.get(k).unwrap()))
}

// later, in main:
for (_k, v1, v2) in iteratemaps::iterate_maps(&m1, &m2) {
    println!("{:?}, {:?}", v1, v2);
}

最后,一个不相关的说明:在 Rust 中,您可以使用 mod modname { ... block ...} 语法指定内联模块。这将允许您在问题的一个 sn-p 中提供整个代码,如 here 所示。

【讨论】:

    猜你喜欢
    • 2020-11-20
    • 2020-06-15
    • 1970-01-01
    • 2014-05-31
    • 2012-12-27
    • 2017-12-01
    • 2015-06-22
    • 2021-08-24
    • 1970-01-01
    相关资源
    最近更新 更多