Как получить ключ из ссылки на хеш-элемент - PullRequest
4 голосов
/ 01 августа 2010

предположим, $my_ref = \$hash{'mary'}; #my_ref - это контрольная точка для хеш-элемента.
....
позже, как я могу использовать $my_ref, чтобы получить ключ хеш-элемента, на который он указывает?т.е. как получить строку 'mary' из $my_ref?

Я задаю этот вопрос, потому что у меня есть несколько групп списка имен пользователей, некоторые имена пользователей появляются в нескольких группах, которые занимают память.Поэтому я решил создать общий список имен пользователей и позволить этим группам хранить только ссылку на соответствующее имя пользователя, а не имя пользователя.

например, изначально,

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

Здесь вы видите, что 'mary' и 'tom' показаны как group1, так и group2, которые занимают память.(заметьте, мне все равно значение в этом примере, значение здесь только потому, что структура данных является хешем).Итак, чтобы уменьшить память, я хочу, чтобы в общем списке хранились все имена пользователей:

%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. по ссылке. Я могу сразу же получить доступ к имени пользователя, не ища его.

Но как я могу получить имя пользователя из группы?

Если я использую @my_ref = keys %group1, я думаю, что получу значение «Мэри», но не «Мэри».

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

Ответы [ 4 ]

5 голосов
/ 01 августа 2010
  1. Ссылка не является целым числом;это SV, так что это будет что-то вроде 24 байта, а не 4.

  2. Не то, чтобы это имело значение, потому что вы не храните ссылок, потому что хеш-ключами всегда являются строки .Ключи ваших %group1 и т. Д. Хешей на самом деле являются строками, которые выглядят как «HASH (0x19838e2)», что бесполезно.

  3. Не то, чтобы это имело значение, поскольку Perl достаточно уменне тратьте память, если одни и те же строки используются в качестве ключей в нескольких хэшах.Правильно, если бы вы просто делали вещи простым, очевидным и разумным способом, perl использовал бы на меньше памяти , чем при работе со сложными вещами, которые вы пытаетесь сделать.

4 голосов
/ 01 августа 2010

Извините, хэши не работают таким образом.Вы не экономите память, используя ссылку вместо строки в качестве ключа хеширования, и, кроме того, вы:

  1. усложняете поиск данных в хэше (скрыто)
  2. мешает внутренней оптимизации хэша в Perl (используя алгоритм хеширования для обеспечения O (1) поиска внутри того, что фактически является списком).

В любомВ этом случае хеш-ключом является скаляр , который необходимо где-то хранить.Используя ссылку в качестве ключа хеширования, теперь вам нужно не только сохранить ссылку в хеше, но и значение, на которое она ссылается, поэтому вы теперь используете more memory.

Что заставило вас поверить в то, что вы сохраняли память своим, кашлем , новым подходом?Вы запускали профилировщик памяти для разных реализаций?

Как правило, вы не можете получить из хеша значение обратно к его ключу (хотя вы можете обходить хеш-таблицу линейноищу его, если бы он был уникальным).Если вы хотите отслеживать как хэш-ключ, так и значение, вам нужно сделать это самостоятельно.Вот некоторые общие подходы:

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

Пожалуйста, прочитайте о том, как работают хеши, в руководстве .Вы также можете прочитать о клавишах и каждой функции.

1 голос
/ 01 августа 2010

Хеш - это средство связывания имен со скалярами.Если у вас есть хеш и ключ, у вас есть скаляр, а не ссылка на хэш-корзину или что-то в этом роде.

my $value = $hash{name};

Это просто скаляр.

my $ref = \$hash{name};

Это просто ссылка на скаляр.Не более способный содержать информацию, позволяющую вам вернуться к хеш-ключу, чем анонимная ссылка может сказать вам, какое имя может быть в таблице символов или лексической панели (без какой-либо помощи).

0 голосов
/ 16 марта 2015

Попробуйте подумать об этом, как о таблицах базы данных. Иметь пользовательскую «таблицу» / хеш, которая связывает идентификатор пользователя с информацией о пользователе, а другие хеши используют идентификатор пользователя вместо информации пользователя.

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

Затем вы могли бы заставить свои списки групп использовать числа вместо имен / имен пользователей.

Тем не менее, я думаю, что вы делаете больше работы для себя, чем необходимо. Вы действительно столкнулись с проблемой с этой программой, использующей слишком много памяти? Наличие дублирующих ключей не является проблемой, если ваши ключи не содержат строки очень большого размера.

Если у вас есть тысяча разных имен пользователей (все 100 символов или меньше) и в совокупности существует 10 000 отношений между пользователем и группой, то у вас есть только:

100 байт * 10 000 = 1 МБ

И, честно говоря, большинство имен составляют 1/5 от этого размера: 200 КБ

Мое предложение будет беспокоиться об этом, только если у вас много МБ информации (скажем, 500 или более).

...