如何从哈希元素的引用中获取键

时间:2010-08-01 01:28:46

标签: perl reference hashref

假设$my_ref = \$hash{'mary'}; #my_ref是哈希元素的参考点 ....
稍后,我如何使用$my_ref检索它指向的哈希元素的键?即如何从$my_ref获取字符串'mary'?

我问这个问题是因为我有几组用户名列表,一些用户名出现在多个消耗内存的组中。所以我决定创建一个通用的用户名列表,让这些组只存储对相应用户名的引用而不是用户名。

e.g。最初,

%group1 = {'mary'=>1, 'luke'=1,'tom'=1,...}  
%group2 = {'mary'=>1, 'sam'=1,'tom'=1,...}

在这里,您会看到'mary'和'tom'都显示在消耗内存的group1group2中。 (注意我不关心这个例子中的值,这里的值只是因为数据结构是一个哈希值)。因此,为了减少内存,我希望有一个公共列表存储所有用户名:

%common_hash = {'mary'=>1, 'luke'=1,'tom'=1,'sam'=1...};  
$ref1 = \$common_hash{'mary'};  
$ref2 = \$common_hash{'luke'};  
$ref3 = \$common_hash{'tom'};  
$ref4 = \$common_hash{'sam'};

组仅存储哈希元素的引用:

%group1 = {$ref1=>1, $ref2=1,$ref3=1,...};  
%group2 = {$ref1=>1, $ref4=1,$ref3=1,...}; 

我认为这种方法可以节省大量内存,因为:

  1. 一个用户名一次不存储多次;
  2. groups存储引用(整数)而不是字符串(在我的例子中,每个用户名的长度平均为30个字节,而每个整数只有4个字节(32位sys。)或8个字节(64位sys) 。))(顺便说一句,如果一个整数不使用4个字节或8个字节,请纠正我。)
  3. 使用引用我可以立即访问用户名而无需查找。
  4. 但是如何从组中获取用户名?

    如果我使用@my_ref = keys %group1,我想我会得到'mary'的价值,但不会'mary'。

    $result = $($my_ref[0]);
    

4 个答案:

答案 0 :(得分:5)

  1. 引用不是整数;它是一个SV,所以它将是24字节而不是4字节。

  2. 并不重要,因为您不是存储引用,因为哈希键始终是字符串。你的%group1等哈希的键实际上是看起来像“HASH(0x19838e2)”的字符串,这是没用的。

  3. 这并不重要,因为Perl非常聪明,可以避免浪费内存,如果相同的字符串用作多个哈希中的键。这是正确的,如果你只是用简单,明显,明智的方式做事,perl将使用更少的内存而不是你想要做的复杂事情。

答案 1 :(得分:4)

抱歉,哈希不能那样工作。您不是通过使用引用而不是字符串作为哈希键来保存任何内存,而且您是:

  1. 使得更难在哈希中找到数据(它被模糊)
  2. 妨碍Perl的内部哈希优化(使用哈希算法在有效列表中提供O(1)查找)。
  3. 在任何一种情况下,散列键都是标量,需要存储在某处。通过使用引用作为哈希键,现在您不仅需要将引用存储在哈希中,还需要存储引用的值,因此您现在使用 more 内存。

    是什么让你相信你通过咳嗽这种新颖的方法来挽救记忆?您是否针对不同的实现运行内存分析器?

    通常,您无法从哈希的返回到(尽管您可以遍历哈希表,线性查找它,如果它是唯一的)。如果要跟踪哈希键和值,则需要自己完成。一些常见的方法是:

    # iterate through the table by key
    foreach my $key (keys %hash)
    {
         # here we have both the key and its corresponding value
         print "value at key $key is $hash{$key}\n";
    }
    
    # iterate through the table by keys and values
    while (my ($key, $value) = each %hash)
    {
         print "value at key $key is $value, which is the same as $hash{$key}\n";
    }
    

    请阅读manual中哈希的工作原理。您还可以阅读keyseach函数。

答案 2 :(得分:1)

哈希是一种将名称与标量相关联的方法。如果你有一个哈希和一个键,你有一个标量,而不是对哈希桶或类似的东西的引用。

my $value = $hash{name};

只是一个标量。

my $ref = \$hash{name};

只是对标量的引用。不再能够包含允许您回溯跟踪散列键的信息而不是匿名引用可以告诉您符号表或词汇表上的名称(没有一些帮助)。

答案 3 :(得分:0)

尝试将其视为数据库表。有一个用户"表" / hash将用户ID与用户信息相关联,并让其他哈希使用用户ID,而不是用户的信息。

my $userid = 5;
$user->{$groupid};
# would be the hash element for that user with a user id 

然后,您可以使您的组列表使用数字而不是名称/用户名。

但是,我认为你正在为自己做更多的工作而不是需要。你是否真的遇到过使用太多内存的程序问题?除非您的密钥包含非常大的字符串,否则重复密钥不是问题。

如果您有一千个不同的用户名(所有100个字符或更少)并且合并,则有10,000个用户/组关系,那么您只有:

100字节* 10,000 = 1MB

说实话,大多数名字是这个尺寸的1/5:200 KB

我的建议是,只有当你有很多MB信息(比如500或更多)时才会担心这个问题。