ハッシュ

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

ハッシュの宣言と初期化

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

ハッシュを利用する前に、その変数がハッシュであることを宣言する必要がある。以下のように行う。

# ハッシュの宣言
my %hash = ();

# ハッシュのリファレンスの宣言
my $hash_ref = {}; 

宣言したハッシュに対して、以下のように値を代入する。

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

# 後から追加する場合
%hash = (%hash, 'CCC' => 'P', 'CAC' => 'H');

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

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

# 後から追加する場合
$hash_ref = {%{$hash_ref}, 'CCC' => 'P', 'CAC' => 'H'};

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

delete $hash{'CCC'};            # ハッシュのキーと値を消去

delete $hash_ref->{'CCC'};      # ハッシュのリファレンスのキーと値を消去

ハッシュの取り出し

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


# キーが CAC に対応する値を取得
print $hash{'CAC'};

# キーが GGG に対応する値を取得
print $hash_ref->{'GGG'};

すべてのキー、あるいはすべての値を取得する場合は keysvalues または each を利用する。次は while 文と each を利用してキーと値の両方を取得する例である。

#ハッシュ
while (my ($key, $value) = each(%hash)) {
  print "key:$key   value:$value";
}


#ハッシュのリファレンス
while (my ($key,$value) = each(%{$hash_ref})) {
  print "key:$key   value:$value";
}

for 文と keys を利用して、キーと値を取得する例。

#ハッシュ
for my $key (keys %hash) {
  print "key:$key   value:$hash{$key}";
}


#ハッシュのリファレンス
for my $key (keys %{$hash_ref}) {
  print "key:$key   value:$hash_ref->{$key}";
}

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

ハッシュのハッシュという多階層のハッシュは、Perl のリファレンスを利用して実現できる。まず、最初に 1 階層目のハッシュを宣言する。次に、そのハッシュにキーと値を代入する。値は空のハッシュのリファレンスとする。このようにする 2 階層からなるハッシュが作成できる。

# 1 階層目のハッシュ
my $hash_ref = {};

# key1 キーに対応する 2 階層目のハッシュ
$hash_ref->{'key1'} = {};

# key1 キーに対応する 2 階層目のハッシュに値を代入
$hash_ref->{'key1'}->{'subKey1'} = 'value11';
$hash_ref->{'key1'}->{'subKey2'} = 'value12';

# key2 キーに対応する 2 階層目のハッシュ
$hash_ref->{'key2'} = {};
$hash_ref->{'key2'}->{'subKey1'} = 'value21';
$hash_ref->{'key2'}->{'subKey2'} = 'value22';

すべての要素取得するときは、ハッシュの時と同様に for 文あるいは while を用いる。この場合、ハッシュが 2 階層となっているため、for 文は 2 回繰り返す必要がある。

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

ソート

ハッシュからすべての要素を取得するとき、その順はランダムである。配列とは異なり、1、2、3、などのように添字が設けられていない。そのため、保存した順にデータを取得したい場合は不可能である。しかし、キーまたは値をソートしてから出力することが可能である。

キーのソート

keyssort を利用して、ソートする。

# キーにはAccession番号、値には塩基配列の長さを格納したハッシュ
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";
}

値のソート

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


# キーにはAccession番号、値には塩基配列の長さを格納したハッシュ
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 }
];

# 配列中のハッシュをハッシュの値(length)について並べ替える
@{$sorted_arr} = sort {$a->{length} <=> $b->{length}} @{$arr};