4

$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. 1つのユーザー名が複数回ではなく1回メモリに保存されます。
  2. groupsは、文字列ではなく参照(整数)を格納します(私の場合、各ユーザー名の長さは平均30バイトですが、各整数は4バイト(32ビットシステム)または8バイト(64ビットシステム)のみです) (ところで、整数が4バイトまたは8バイトを使用しない場合は修正してください。)
  3. 参照を使用すると、ユーザー名を探すことなくすぐにアクセスできます。

しかし、どうすればグループからユーザー名を取得できますか?

を使用する@my_ref = keys %group1と、「mary」の値は取得されますが、「mary」の値は取得されないと思います。

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

4 に答える 4

5
  1. 参照は整数ではありません。これはSVなので、4バイトではなく24バイトのようになります。

  2. ハッシュキーは常に文字列であるため、参照を保存していないため、重要ではありません。ハッシュなどのキーは、実際には「HASH(0x19838e2)」のような文字列であり、役に立たない。%group1

  3. 同じ文字列が複数のハッシュでキーとして使用されている場合、Perlはメモリの浪費を回避するのに十分賢いので、それは重要ではありません。そうです、もしあなたが単純で、明白で、賢明な方法で物事をやったとしたら、perlはあなたがやろうとしている複雑なことよりも少ないメモリを使うでしょう。

于 2010-08-01T02:28:12.303 に答える
4

申し訳ありませんが、ハッシュはそのようには機能しません。文字列の代わりに参照をハッシュキーとして使用してメモリを節約することはありません。さらに、次のようになります。

  1. ハッシュ内のデータを見つけるのが難しくなります(あいまいになります)
  2. Perlの内部ハッシュ最適化の邪魔になります(ハッシュアルゴリズムを使用して、事実上リストであるものの内部でO(1)ルックアップを提供します)。

いずれの場合も、ハッシュキーはスカラーであり、どこかに格納する必要があります。参照をハッシュキーとして使用することにより、参照をハッシュに格納するだけでなく、参照している値も格納する必要があるため、より多くのメモリを使用するようになります。

、斬新なアプローチで記憶を節約していると信じたきっかけは何ですか?さまざまな実装に対してメモリプロファイラーを実行しましたか?

一般に、ハッシュのからそのキーに戻ることはできません(ただし、ハッシュテーブルが一意である場合は、ハッシュテーブルを直線的にトラバースして検索することはできます)。ハッシュキーと値の両方を追跡したい場合は、自分で行う必要があります。一般的なアプローチは次のとおりです。

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

マニュアルでハッシュがどのように機能するかを読んでください。キー機能についても読むことができます。

于 2010-08-01T01:53:09.920 に答える
1

ハッシュは、名前をスカラーに関連付ける手段です。ハッシュとキーがある場合は、ハッシュバケットなどへの参照ではなく、スカラーがあります。

my $value = $hash{name};

単なるスカラーです。

my $ref = \$hash{name};

スカラーへの単なる参照です。匿名の参照がシンボルテーブルまたは字句パッド(助けなしで)に何が含まれているのかを知ることができるのと同じように、ハッシュキーへのバックトレースを可能にする情報を含めることはできません。

于 2010-08-01T02:25:35.253 に答える
0

データベーステーブルのように考えてみてください。ユーザーIDをユーザーに関する情報に関連付けるユーザー「テーブル」/ハッシュを用意し、他のハッシュでユーザー情報の代わりにユーザーIDを使用するようにします。

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

次に、グループリストに名前/ユーザー名の代わりに番号を使用させることができます。

しかし、あなたは必要以上に自分のために仕事をしていると思います。あなたは実際にあまりにも多くのメモリを使用しているこのプログラムで問題に遭遇しましたか?キーに非常に大きなサイズの文字列が含まれていない限り、キーが重複していても問題はありません。

1000の異なるユーザー名(すべて100文字以下)があり、それらを組み合わせると、10,000のユーザー/グループの関係があり、次のようになります。

100バイト*10,000= 1MB

そして正直なところ、ほとんどの名前はそのサイズの1/5です:200 KB

私の提案は、あなたがたくさんのMBの情報(例えば500以上)を持っている場合にのみこれについて心配することです。

于 2015-03-16T15:31:40.307 に答える