在Perl中,哈希表的键和值是否具有相同的“顺序”?

4
我可以理解在Perl中哈希表是无序的。我的疑虑是,我能否依赖于键和值之间的索引关系。
比如说,我有一个这样的哈希表:
my %h = ("a" => 1, "b" => 2, "c" => 3, "d" => 4);

如果我执行keys %h,可能会得到以下结果:

("b", "a", "d", "c")

我是否可以保证values %h的顺序与键值对应的顺序相同?我能期望吗?

(2, 1, 4, 3)

那么keys %hvalues %h之间是否存在任何索引关系?


2
@DaveCross,“RTFM”并不是一个真正的答案。 - Mulan
2
这就是为什么我将其写成了注释的原因 :-) 但是,说真的,在这种情况下我认为它是合理的。你问题的答案在FM中已经清楚地写出来了。你所接受的答案引用了FM中的内容。所以,在这里我认为这是一个合理的答案。 - Dave Cross
如果在文档中找不到这样的信息,请提交错误报告。 - Brad Gilbert
2个回答

11

是的。 只要哈希表没有改变(插入或删除),keysvalueseach将保持相同的顺序:

只要给定的哈希表未被修改,您可以依赖于keysvalueseach重复按照相同顺序返回。

– 引自perldoc -f keys

因此,您可以安全地复制一个哈希表,例如:

my %orig = ...;
my %copy;
@copy{keys %orig} = values %orig;

1
太好了。这正是我需要知道的 ^.^ - Mulan
但是调用之间顺序会改变。 - Chloe

3

尽管键和值返回其内容的顺序可能因计算机和实现而异,但你可以确信它们将产生相同的顺序。或者,您可以使用函数“each”同时获取键和值:

while (($key,$value) = each %ENV) {
    print "$key=$value\n";
}

使用each的好处在于,Perl不需要一次性分配足够的内存来存储所有的键和值,因此如果您正在迭代遍历一个大型哈希表,它将更加高效。

请注意,根据您的 Perl 版本,获取键列表,然后在哈希表中查找每个键可能比使用 each 更快。我不知道如何或为什么,但在“优化”之前请先进行测试。 - Mark Reed
谢谢,马克。我相信你所说的关于keyseach的区别。我认为当Perl实现foreach my key (keys %myhash)时,它并不会一次性展开所有的键,而是逐个展开。 - Mark Nodine
@Mark Nodine,“foreach my key(keys%myhash)”会将键列表展平。 - ikegami
@ikegami - 你是什么意思?哈希表的键在插入时被字符串化;没有需要展开的东西。 - Mark Reed
@Mark Reed,将列表展平意味着评估列表的每个项目(在这种情况下,只有“键”),以形成堆栈上的“平面”标量列表。例如,@a,@b,@c创建由@a@b@c元素组成的“平面”列表。Mark Nodine说他认为foreach my key (keys %myhash)被优化为类似于while(my($key)=keys(%myhash))的东西,我告诉他不是这样的。 - ikegami
@ikegami:你显然是正确的,当迭代时perl不会优化键。我刚刚做了一个实验,生成了一个包含所有键“aaaaa”..“zzzzz”的哈希表,使用keys实现比each多使用了50%的内存,但只慢了5%。我认为perl不能进行这样的优化,因为你可能会在循环中修改键。 - Mark Nodine

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