How to get the key from a hash element link

suppose $my_ref = \$hash{'mary'}; #my_ref is a reference point to a hash element.
....
later, how can I use $my_ref to retrieve the key of the hash element that it points to? How to get the string "mary" from $my_ref ?

I ask this question because I have several groups of username lists, some usernames appear in several groups that consume memory. Therefore, I decided to create a common list of usernames, and let these groups retain a link only to the corresponding username, not to the username.

eg. initially

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

Here you see 'mary' and 'tom' are shown in both group1 and group2 , which consume memory. (note: the value in this example is not important to me, the value here is only because the data structure is a hash). To reduce the amount of memory, I want all user names to be stored in the general list:

 %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'}; 
Groups

save only the hash element link:

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

I think this approach can save a lot of memory because:

  • one username is stored in memory once several times;
  • groups store a link (an integer), not a string (in my case, the length of each username is an average of 30 bytes, and each integer is only 4 bytes (32-bit system) or 8 bytes (64-bit system.)) (BTW, correct me if the integer doesn't use 4 bytes or 8 bytes.)
  • using the link, I can immediately get the username without looking for it.

But how can I get a username from a group?

If I use @my_ref = keys %group1 , I think I get the value "mary", but not "mary".

 $result = $($my_ref[0]); 
+4
source share
4 answers

Sorry, hashes do not work. You do not save memory using a link instead of a string as a hash key, and in addition, you:

  • makes it difficult to find data in a hash (it is hidden)
  • interferes with optimizing Perl's internal hash (using a hash algorithm to provide O (1) lookup inside what is an effective list).

In any case, the hash key is a scalar that needs to be stored somewhere. Using the link as a hash key, now you need to not only store the link in a hash, but also the value that it refers to, so now you are using more memory.

What made you believe that you saved your memory with your cough, a new approach? Did you run a memory profiler for different implementations?

As a rule, you cannot get the hash value back to its key (although you can traverse the hash table linearly looking for it if it was unique). If you want to track both the hash key and value, you need to do it yourself. Some common approaches:

 # 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"; } 

Read how hashes work in the manual . You can also read about keys and each .

+4
source
  • A reference is not an integer; this is SV, so it will be approximately 24 bytes, not 4.

  • It doesn’t matter because you do not store links, because hash keys are always strings . The keys of your hashes are %group1 , etc. They are strings that look like "HASH (0x19838e2)", which is useless.

  • It doesn't matter, because Perl is smart enough to avoid memory loss if the same lines are used as keys in multiple hashes. That's right, if you were just doing the simple, obvious, reasonable way, perl would use less memory than with the difficult task you are trying to do.

+5
source

A hash is a means of associating names with scalars. If you have a hash and a key, you have a scalar, not a link to a hash bucket or something like that.

 my $value = $hash{name}; 

This is just a scalar.

 my $ref = \$hash{name}; 

This is just a link to a scalar. It can no longer contain information that allows you to track the hash key trace than an anonymous link, can tell you what name can be in the symbol table, or the lexical panel (without any help).

+1
source

Try to think of it as a database table. Have a custom "table" / hash that associates the user ID with user information, and other hashes use the user ID, not user information.

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

Then you can make group lists usable numbers instead of usernames / usernames.

However, I think you are doing more work for yourself than you need. Are you really having a problem with this program using too much memory? Having duplicate keys is not a problem if your keys do not contain large strings.

If you have a thousand different usernames (all 100 characters or less) and combined, there are 10,000 relationships between the user and the group, then you only have:

100 bytes * 10,000 = 1 MB

And frankly, most names are 1/5 of this size: 200 KB

My suggestion would be to worry about this only if you have a lot of MB of information (say 500 or more).

0
source

All Articles