Perl のハッシュはキーと値をペアとして保存できる変数

ハッシュ

ハッシュは、配列のように複数の要素を格納できる。しかし、配列は各要素を添え字で管理しているのに対して、ハッシュは各要素をキーで管理している。そのため配列の各要素には順序があるのに対して、ハッシュの各要素には順序がない。for 文などでハッシュからすべてのキーを取り出すとき、キーはランダムに取り出される。

ハッシュは辞書のような使い方ができる。例えば、遺伝コードをハッシュ化することによって、コドンを与えると、そのコドンに対応するアミノ酸を出力させるような機能を実現できる。あるいは、Accession 番号と塩基配列をハッシュ化することにより、Accession 番号を与えると、それに対応した塩基配列を引くことができる。このように、コドンや Accession 番号などを「キー」とよび、それに対応するアミノ酸や塩基配列を「値」とよぶ。

ハッシュの宣言と初期化

ハッシュ

Perl のハッシュは、変数名の前に % を付ける識別する。ハッシュの要素を括弧を利用して代入する。


my %hash = ();

ハッシュにキーと値を代入するとき、次のようにまとめて代入したり、1 つずつ代入したりすることができる。

%hash = ('AUG' => 'M', 'GGG' => 'G', 'CAA' => 'Q');
$hash{'CGA'} = 'R';
$hash{'CCA'} = 'P';

ハッシュのリファレンス

ハッシュのリファレンスは、変数名の前に $ を付け、要素は大括弧を利用して代入する。

my $hash_ref = {}; 

キーと値の代入は以下のようにできる。

$hash_ref = {'AUG' => 'M', 'GGG' => 'G', 'CAA' => 'Q'};
$hash_ref = {%{$hash_ref}, 'CCC' => 'P', 'CAC' => 'H'};
$hash_ref->{'CGA'} = 'R';
$hash_ref->{'CGA'} = 'P';

ハッシュの取り出し

ハッシュ

ハッシュの構造はキーと値が 1 セットで保存されている。値の取得は「キー」を指定して行う。

my %hash = ('AUG' => 'M', 'GGG' => 'G', 'CAA' => 'Q');

print $hash{'CAA'};
## Q

ハッシュに保存されているすべてのキーと値を取り出す場合は for 文あるいは while 文を利用する。

while (my ($key, $value) = each(%hash)) {
    print "$key   $value";
}

for my $key (keys %hash) {
    print "$key   $hash{$key}";
}

ハッシュのリファレンス

ハッシュのリファレンスもハッシュと同じ要領で、キーと値を取り出すことができる。

$hash_ref = {'AUG' => 'M', 'GGG' => 'G', 'CAA' => 'Q'};

print $hash_ref->{'GGG'};

while (my ($key,$value) = each(%{$hash_ref})) {
    print "$key   $value";
}

for my $key (keys %{$hash_ref}) {
    print "$key   $hash_ref->{$key}";
}

ハッシュのキーの削除

キーと値を消去したい場合は delete を利用する。

delete $hash{'CCC'};
delete $hash_ref->{'CCC'};

ハッシュのハッシュ(hash of hashes)

ハッシュのハッシュのように 2 階層のハッシュを作成する必要がある場合は、リファレンスを利用する。まず、1 階層目のハッシュを宣言し、キーを任意の文字列とし、値をハッシュのリファレンスを保存する。こうすることで、1 階層目の値が、2 階層目のハッシュのリファレンスとなる。

my $hash_ref = {};

$hash_ref->{'key1'} = {};

$hash_ref->{'key1'}->{'subKey1'} = 'value11';
$hash_ref->{'key1'}->{'subKey2'} = 'value12';

$hash_ref->{'key2'} = {};
$hash_ref->{'key2'}->{'subKey1'} = 'value21';
$hash_ref->{'key2'}->{'subKey2'} = 'value22';

ハッシュのハッシュからすべての値を取り出す時、for 文または while 文を入れ子にして実行する。

for $mainKey ( keys %{$hash_ref} ){
    for $subKey ( keys %{$hash_ref->{$mainKey}} ){
        print "$mainKey, $subKey, $hash_ref->{$mainKey}->{$subKey}";
    }
}

ソート

for 文あるいは while 文でハッシュからすべてのキーと要素を取り出す時、取り出される順番はランダムである。これは、ハッシュは配列と異なり、0、1、2、のような添え字が設けられていないからである。そのため、保存した順でデータを取得することは不可能である。しかし、キーあるいは値の文字列をソートすることは、可能である。

キーのソート

keyssort を利用して、ハッシュのキーをソートする。

my %hash = (
    'XX0123456' => 455, 
    'XX0123437' => 976,
    'XX0123458' => 321
);

for my $key (sort keys %hash) {
    my $value = $hash{$key};
    print "key: $key    value: $value";
}

ハッシュのリファレンスの場合は次のようにソートする。

for my $key (sort keys %{$hash_ref}) {
    my $value = $hash_ref->{$key};
    print "key: $key    value: $value";
}

値のソート

ハッシュの値についてソートを行う場合は以下のようにする。

my %hash = (
    'XX0123456' => 455, 
    'XX0123457' => 976,
    'XX0123458' => 321
);

## 昇順
foreach my $key (sort {$hash{$a} <=> $hash{$b}} keys %hash){
    print $key, $hash{$key}, "\n";
}

## 降順
foreach my $key (sort {$hash{$b} <=> $hash{$a}} keys %hash){
    print $key, $hash{$key}, "\n";
}

ハッシュのリファレンスの場合は、次のようにする。

foreach my $key (sort {${$ref}{$b} <=> ${$ref}{$a}} keys %{$ref} ){
    print $key, $ref->{$key}, "\n";
}

ハッシュの配列のソート

配列の中にハッシュが保存され、そのハッシュの値を元に、配列をソートする場合は以下のようにする。

my $arr = [
    { gi => 'XX0123456' , length => 455 }
    { gi => 'XX0123457' , length => 976 }
    { gi => 'XX0123458' , length => 321 }
];

@{$sorted_arr} = sort {$a->{length} <=> $b->{length}} @{$arr};