【问题标题】:What do you get if you evaluate a hash in scalar context?如果您在标量上下文中评估哈希,您会得到什么?
【发布时间】:2011-09-15 07:39:58
【问题描述】:

考虑以下 sn-p:

use strict;
use warnings;

my %a = ( a => 1,
          b => 2,
          c => 'cucu',
          d => undef,
          r => 1,
          br => 2,
          cr => 'cucu',
          dr => '321312321',

        );

my $c = %a;

print $c;

这个结果是5/8,我不明白这代表什么。我在某处读到这个 ​​fraction 看起来结果中的一个数字可能代表哈希中的桶数,但显然情况并非如此。

有谁知道如何在标量上下文中评估 perl 哈希?

编辑

我添加了一些其他哈希来打印:

use strict;
use warnings;

use 5.010;


my %a = ( a => 1,
          b => 2,
          c => 'cucu',
          d => undef,
          r => 1,
          br => 2,
          cr => 'cucu',
          dr => '321312321',

        );

my $c = %a;

say $c; # 5/8


%a = ( a => 1,
       b => 21,
       c => 'cucu',
       br => 2,
       cr => 'cucu',
       dr => '321312321',

      );

 $c = %a;

say $c; # 4/8

%a = ( a => 1,
       b => 2,
       c => 'cucu',
       d => undef,
       r => 1,
       br => 2,
       cr => 'cucu',
       dr => '321312321',
       drr => '32131232122',
      );

 $c = %a;

say $c; #6/8

那么,您将像 a => 1 这样的“元组”称为哈希中的存储桶吗?在那种情况下,为什么最后一个哈希有 9 个“元组”时仍然有 8 作为分母?

感谢大家到目前为止的回复:)

【问题讨论】:

标签: perl


【解决方案1】:

[OP 询问 Perl 5.26 之前标量上下文中哈希返回的字符串格式。从 Perl 5.26 开始,标量上下文中的散列不再返回这种格式的字符串,而是返回散列中的元素数。如果需要这里讨论的值,可以使用Hash::Utilbucket_ratio()]

哈希是一个链表数组。散列函数将键转换为一个数字,该数字用作存储值的数组元素(“桶”)的索引。链表处理多个键哈希到同一个索引(“冲突”)的情况。

分数的分母是桶的总数。

分数的分子是包含一个或多个元素的桶数。

对于元素个数相同的哈希,数字越大越好。返回 6/8 的冲突比返回 4/8 的冲突更少。

【讨论】:

  • 这不适用于 Perl 5.25 和更新版本。请参阅我对新行为的回答。
  • @Daniel Böhmer,已调整。
  • @ruakh,bucket_ratio 当时不存在的事实并没有使我所说的不正确。 :) 但我接受替代措辞。 (通过调整。我避免调用 Perl subs“函数”,因为文档使用“函数”来引用命名运算符。c.f. perlfunc。)
【解决方案2】:

来自perldoc perldata

如果您在标量上下文中评估哈希,如果哈希返回 false 是空的。如果有任何键/值对,则返回 true;更多的 准确地说,返回的值是一个字符串,由 已使用的桶和分配的桶数,用 a 分隔 斜线。

在您的情况下,您有五个值(12''cucu'undef'321312321')已被八个键(abc,d,r,br,cr,和dr)。

【讨论】:

  • 再说一次,这种模式是否普遍适用还不清楚:当我运行my %h=("a"=>1,"b"=>2,"c"=>3);my $a=%h;print "$a\n"; 时,我得到3/8 的输出。 =/
  • 他碰巧有 5 个不同的值只是一个巧合。你可以给每个键一个不同的值,Perl 仍然会报告 5/8。桶的使用仅取决于哈希中的键。
  • @Jack:解释是错误的。使用的桶越多越好。典型哈希表中的存储桶包含一个键(它是用户提供的键的哈希)和一个值列表,其中包含由同一键映射的所有值(不同的键被称为冲突)。列表越长,访问时间就越长。
  • @Jack:是3/8,因为三个键使用三个桶,总共八个桶是 perl 为哈希分配的最小数字。
  • @JackManey:您可以编辑您的答案以纠正错误。如果你这样做,我会支持你的答案,因为与接受的答案不同,你实际上引用了文档。
【解决方案3】:

使用的桶的数量开始大约是键的数量;分配的桶始终是 2 > 键数的最低幂。 5 个键将返回 5/8。唯一键的数量越多,增长越慢,因此仅包含 64 个键/值对的列表 (1..128) 的哈希 %h 会以某种方式获得 50/128 的标量值。

但是,一旦散列分配了它的存储桶,即使您缩小散列,它们也将保持分配状态。我刚刚用 9 对创建了一个哈希 %h,因此是 9/16 标量;然后当我将 %h 重新分配为只有一对时,它的标量值为 1/16。

这实际上是有道理的,因为它可以让您测试哈希的大小,就像简单数组的标量一样。

【讨论】:

  • 这取决于您提供的密钥。某些键可能会发生冲突,导致仅使用 50 个存储桶,而不是您的特定示例中的 64 个。您可以生成填充 64 个存储桶或仅一个存储桶的密钥(这对性能不利)。
【解决方案4】:

自 Perl 5.25 以来,该行为发生了变化。见perldata for Perl 5.26

在 Perl 5.25 之前,返回的值是一个字符串,由 使用的桶数和分配的桶数,由 一个斜线。这仅在确定 Perl 的 内部散列算法在您的数据集上表现不佳。为了 例如,您将 10,000 个东西放在哈希中,但在计算 %HASH 标量上下文显示1/16,这意味着只有十六分之一 buckets 已被触摸,大概包含了你所有的 10,000 个 项目。这不应该发生。

从 Perl 5.25 开始,返回值更改为 哈希。如果您需要访问旧行为,您可以使用 Hash::Util::bucket_ratio() 代替。

【讨论】:

  • 这个问题特别是关于 5.26 之前返回的字符串的含义,而不是关于哈希返回的一般情况。我将在我的答案中包含一条注释,即哈希不再返回 OP 询问的字符串。
  • 你是对的。工作做得很仔细!问题标题仍然是如果你在标量上下文中评估哈希会得到什么?。所以我将把它留在这里,因为它回答了标题中的问题,我最初来到这里的原因是什么。
【解决方案5】:

过分关注这种分数模式(作为哈希内部细节的指标)可能会令人困惑。散列的“标量值”的一个方面可能对每个 Perl 程序都很重要,也就是说,如果它在 布尔上下文中被认为是 true ,看一个例子:

if (%h) {
    print "Entries in hash:\n";
    for my $k (sort keys %h) {
        print "$k: $h{$k}\n";
    }
}

perldoc perldata, section Scalar-values,你可以读到

[...] 布尔上下文只是一种特殊的标量上下文,它不会执行到字符串或数字的转换。

然后,在后面的一些段落中,

如果您在标量上下文中评估哈希,如果哈希返回 false 是空的。如果有任何键/值对,则返回 true [...]

【讨论】:

    猜你喜欢
    • 2012-03-12
    • 2017-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-23
    • 2016-10-25
    • 1970-01-01
    • 2010-11-10
    相关资源
    最近更新 更多