在正确的顺序中哈希键和值

9

我曾经多次看到以下这段代码,用于将一个哈希表连接到另一个哈希表中:

%hash1 = ('one' => "uno");
%hash2 = ('two' => "dos", 'three' => "tres");

@hash1{keys %hash2} = values %hash2;

我曾认为每次调用“values”或“keys”函数时,它们的输出顺序都是随机的。如果这是真的,那么为什么上面的语句能够在两侧正确地获取键和值?
换句话说,在合并两个哈希后,为什么没有机会在%hash1中获得“two”=>“tres”?Perl是否聪明到知道如果在同一行上调用“keys”和“values”,则必须按相同顺序给出键和值?

2
哈希算法的工作方式是在程序的同一次执行中,给定哈希中项目的顺序是随机的,但保证相同。如果数据结构发生变化,则顺序可能会改变。当您第二次调用程序时,不能保证顺序相同。 - simbabque
2个回答

13

请参阅perldoc -f keys

只要给定的哈希未被修改,可以依赖keys、values和each以相同顺序重复返回。


5
哈希表是一个链表数组。哈希函数将关键字转换为数字,用作存储值的数组元素(“桶”)的索引。多个关键字可能会哈希到相同的索引(“冲突”),这种情况由链表处理。 keysvalueseach使用的迭代器按照哈希表中元素的位置返回顺序。我想它会先迭代第一个桶中的链表,然后迭代第二个桶中的链表,依此类推。重要的是,它不会随机迭代哈希表元素的顺序。这就是为什么文档保证以下内容的原因:
只要给定的哈希表未被修改,您可以依赖于keys,values和each重复地返回相同的顺序。
随机的是一个关键字将哈希到哪个桶编号。每个哈希表都有一个随机秘密数来扰动哈希函数。这会导致每个哈希表和每次运行程序中哈希表元素的顺序都不同。
向哈希表添加元素可能会导致桶的数量增加,并且如果其中一个链接列表变得异常长,则可能会触发秘密数更改。这两种情况都会改变哈希表中元素的顺序。
$ perl -le'
   my %h1 = map { $_ => 1 } "a".."j";
   my %h2 = map { $_ => 1 } "a".."j";
   print keys(%$_) for \%h1, \%h1, \%h2, \%h2;
'
hjfeadbigc
hjfeadbigc
bdgcifjhae
bdgcifjhae

$ perl -le'
   my %h1 = map { $_ => 1 } "a".."j";
   my %h2 = map { $_ => 1 } "a".."j";
   print keys(%$_) for \%h1, \%h1, \%h2, \%h2;
'
dcahigjbfe
dcahigjbfe
gihacdefbj
gihacdefbj

  1. 这并不完全是随机的。如果在哈希表中插入两个元素,第二个元素通过迭代器返回的概率要大于50%。
  2. 在旧版本的Perl中,情况并不是那么随机。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接