2.10.3. ハッシュ#

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

ハッシュは辞書のような使い方ができます。例えば、遺伝コードをハッシュ化すると、コドンを与えたときに対応するアミノ酸を出力させることができます。また、Accession 番号と塩基配列をハッシュ化すれば、Accession 番号を指定することで対応する塩基配列を取得できます。このように、コドンや Accession 番号などを「キー」と呼び、それに対応するアミノ酸や塩基配列を「値」と呼びます。

2.10.3.1. 宣言と初期化#

Perl のハッシュは、変数名の前に % を付けて識別します。ハッシュの初期化には括弧を利用します。

my %hash = ();

ハッシュにキーと値を代入する場合は、まとめて代入する方法と、1 つずつ代入する方法があります。

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

2.10.3.2. ハッシュのリファレンス#

ハッシュのリファレンスは、変数名の前に $ を付け、初期化には中括弧を利用します。

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';

2.10.3.3. ハッシュの取り出し#

ハッシュはキーと値のペアで保存されています。値を取得するには、対応するキーを指定します。

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

2.10.3.4. ハッシュのリファレンスの取り出し#

ハッシュのリファレンスも、通常のハッシュと同様にキーと値を取り出すことができます。

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

2.10.3.5. ハッシュのキーの削除#

キーと値を削除したい場合は delete を利用します。

delete $hash_ref->{'CCC'};

2.10.3.6. ハッシュのハッシュ(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}";
    }
}

2.10.3.7. ソート#

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