【发布时间】:2018-02-04 06:30:53
【问题描述】:
我观察到HashMap 具有不同的元素顺序,即使在下一个程序启动时具有相同的数据。看起来HashMap 使用了一些绝对地址来对元素进行排序。如果插入相同的数据,是否还有其他HashMap 实现具有相同的行为?
【问题讨论】:
我观察到HashMap 具有不同的元素顺序,即使在下一个程序启动时具有相同的数据。看起来HashMap 使用了一些绝对地址来对元素进行排序。如果插入相同的数据,是否还有其他HashMap 实现具有相同的行为?
【问题讨论】:
我观察到
HashMap具有不同的元素顺序,即使在下一个程序启动时具有相同的数据。
你不必观察任何东西,这里是documented by HashMap:
默认情况下,
HashMap使用选定的哈希算法来抵抗 HashDoS 攻击。该算法是随机播种的,并尽最大努力从主机提供的高质量、安全的随机源生成此种子,而不会阻塞程序。
值得注意的是,这意味着两个HashMaps 在同一程序运行中具有相同的插入值集可能会有不同的排序:
use std::collections::HashMap;
fn main() {
let a = (0..100).zip(100..200);
let hash_one: HashMap<_, _> = a.clone().collect();
let hash_two: HashMap<_, _> = a.clone().collect();
// prints "false", most of the time
println!("{}", hash_one.into_iter().eq(hash_two));
}
文档还告诉您如何解决该问题:
可以使用
default、with_hasher和with_capacity_and_hasher方法在每个HashMap的基础上替换散列算法。 crates.io 上提供了许多替代算法,例如 fnv crate。
由于我在 twox-hash 工作,我将以此为例:
use std::hash::BuildHasherDefault;
use std::collections::HashMap;
use twox_hash::XxHash;
let mut hash: HashMap<_, _, BuildHasherDefault<XxHash>> = Default::default();
hash.insert(42, "the answer");
assert_eq!(hash.get(&42), Some(&"the answer"));
话虽如此,依赖HashMap的顺序听起来是个坏主意。也许您应该使用不同的数据结构,例如BTreeMap。
在其他情况下,您实际上关心插入的顺序。为此,indexmap crate 是合适的。
【讨论】:
indexmap中的迭代顺序并不是严格的插入顺序。为什么?因为在删除元素时,最后插入的元素与要删除的元素交换。对于给定的插入/删除序列,它仍然是完全确定的。
我相信linked-hash-map 是事实上的板条箱。
【讨论】:
内置的BTreeMap 是一个很好的选择。
我在 assert_eq! 中遇到了类似的问题! diff 每次都是随机顺序,HashMap 调试比较困难,但是 BTreeMap 对 key 进行了排序,所以不存在这个问题。
(来源:https://users.rust-lang.org/t/sort-hashmap-data-by-keys/37095/2)
【讨论】:
将HashMap::with_hasher() 与默认RandomState 以外的其他内容一起使用。
【讨论】: