如何将 HashMap 的值收集到向量中?

Posted

技术标签:

【中文标题】如何将 HashMap 的值收集到向量中?【英文标题】:How do I collect the values of a HashMap into a vector? 【发布时间】:2019-11-05 12:27:59 【问题描述】:

我找不到将HashMap 的值收集到文档中的Vec 的方法。我有score_table: HashMap<Id, Score>,我想把所有的Scores 变成all_scores: Vec<Score>

我很想使用 values 方法 (all_scores = score_table.values()),但它不起作用,因为 values 不是 Vec

我知道Values 实现了ExactSizeIterator 特征,但我不知道如何将迭代器的所有值收集到一个向量中,而无需手动编写一个 for 循环并将向量中的值一个接一个地推入。

我也尝试过use std::iter::FromIterator;,但以如下内容结束:

all_scores = Vec::from_iter(score_table.values());
expected type `std::vec::Vec<Score>`
   found type `std::vec::Vec<&Score>`

感谢Hash map macro refuses to type-check, failing with a misleading (and seemingly buggy) error message?,我改成了:

all_scores = Vec::from_iter(score_table.values().cloned());

它不会对cargo check产生错误。

这是一个好方法吗?

【问题讨论】:

如果你想收藏,为什么不用collect “这是一种好方法吗?” — 关于 Rust(和 C/C++)的一件事是您需要考虑数据的所有权.默认情况下会移动数据,这会更改所有者。如果您不希望所有者更改,则可以传递参考,也可以克隆原始数据。哪种方式“好”取决于您的用例:如果哈希图是数据的所有者,则可能在其他任何地方使用引用(即Vec&lt;&amp;Score&gt;)。但是,当所讨论的类型很小时,克隆通常是正确的做法。 【参考方案1】:

HashMap.into_values 将在值上返回一个拥有迭代器:

let all_scores: Vec<Score> = score_table.into_values().collect();

相比之下,HashMap.values 的迭代器不拥有并返回引用 (&amp;Score) 而不是值。

【讨论】:

【参考方案2】:

如果您不再需要score_table,您可以通过以下方式将Score 值的所有权转让给all_scores

let all_scores: Vec<Score> = score_table.into_iter()
                                        .map(|(_id, score)| score)
                                        .collect();

与@apetranzilla 的克隆方法相比,这种方法会更快并且消耗更少的内存。它还支持任何结构,不仅是实现Clone 的结构。

【讨论】:

【参考方案3】:

Iterator.collect 方法是为这个特定任务设计的。你是对的,如果你想要一个实际值的向量而不是引用,你需要.cloned()(除非存储类型实现Copy,如原语),所以代码如下所示:

all_scores = score_table.values().cloned().collect();

在内部,collect() 只使用FromIterator,但它也推断输出的类型。有时没有足够的信息来推断类型,因此您可能需要明确指定所需的类型,如下所示:

all_scores = score_table.values().cloned().collect::<Vec<Score>>();

【讨论】:

以上是关于如何将 HashMap 的值收集到向量中?的主要内容,如果未能解决你的问题,请参考以下文章

HashMap的内部实现机制,Hash是怎样实现的,什么时候ReHash

HashMap原理 — 扩容机制及存取原理

HashMap源码之常用方法--JDK1.8

HashMap源码分析

Java的HashMap是如何工作的?

Java BAT大型公司面试必考技能视频-1.HashMap源码分析与实现