【问题标题】:Checking two HashMaps for identical keyset in Rust在 Rust 中检查两个 HashMap 是否有相同的键集
【发布时间】:2019-10-29 21:51:54
【问题描述】:

假设我有两个 HashMap(或者,any 映射结构,其键映射到其他东西),map1 和 map2,我想确保它们具有相同的键集。请注意,keys 在地图中是相同的类型,但 valuesnot

我最初的尝试只是:

map1.keys().eq(map2.keys())

并且,虽然这在 第一次 时起作用,但迭代器的 eq 函数(可以理解)似乎按迭代器生成的顺序比较键 ,不是通过检查第二个迭代器中任何地方的键是否存在。这一点,再加上 HashMap::keys() 产生一个迭代器,其中 键的顺序是非确定性的,这意味着即使集合(在集合中理论意义)的键是相同的。

所以,我的下一个尝试是创建一个这样做的函数:

fn keys_match<T:std::cmp::Eq + std::hash::Hash,U,V>(map1:&HashMap<T,U>, map2:&HashMap<T,V>) -> bool {
  // Make sure that map1.keys() ⊆ map2.keys()
  for key in map1.keys() {
    match map2.get(key) {
      None => return false,
      Some(_) => {}
    }
  }
  // If map1.keys() ⊆ map2.keys() and their sizes equal, then the sets are equal
  map1.len() == map2.len()
}

Rust 初学者注意事项:我的第一次尝试实际上是在知道映射中的键是 String 类型的情况下,所以我的函数签名是:

fn keys_match<T,U>(map1:&HashMap<String,T>, map2:&HashMap<String,U>) -> bool

直到我意识到我什至可以通过要求它们具有 Eq 和 Hash 特征来泛化 公共键类型

问题:在 Rust 中有更简洁的方法吗?

【问题讨论】:

  • 不是一个答案,但您可能应该先测试大小,这样如果长度不同,您就不会浪费时间比较密钥。
  • 很好的建议。我想我在试图限制早期返回和限制代码大小方面有点陷入困境,但你是对的,前提是 HashMap::len() 本身不会迭代键(并且取决于您的用例是否倾向于测试大小相同但不同的集合),首先测试长度是一个重要的考虑因素。

标签: rust iterator equality


【解决方案1】:

在 Rust 中有更简洁的方法吗?

fn keys_match<T: Eq + Hash, U, V>(
    map1: &HashMap<T, U>, 
    map2: &HashMap<T, V>,
) -> bool {
    map1.len() == map2.len() && map1.keys().all(|k| map2.contains_key(k))
}

(Playground)

此代码对您的代码进行了三项改进:

  • 使用Iterator::all 可以大大缩短代码。
  • 使用HashMap::contains_key 比检查HashMap::get 的结果要好。
  • 这会首先检查长度,因为这是一个廉价的测试,应该先完成。

【讨论】:

  • 我从来没有遇到过迭代器的 .all() 函数(也没有 .any())。我现在知道在其他支持迭代器的语言中寻找它。
  • @Jemenake 是的,Iterator 的许多方法都很棒,可以真正缩短您的代码。并使其更具可读性 IMO :)
  • map1.keys().any(|k| !map2.contains_key(k)) 可能会更高效(O(n) 的性能最差情况相同,但最好情况要好得多)。
  • @TeymourAldridge 应该没有区别。如果all 中的闭包返回false,它也不会进一步尝试并立即停止。 allany 实际上只是彼此的倒置版本。
  • @TeymourAldridge 没问题!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-26
  • 2019-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多