第17回awkの連想配列

講座「文系のためのawkプログラミング入門」

今回のテーマは連想配列です。連想配列は、C言語やBasic言語にもない独特の配列です。C++ や perlなど比較的新しい言語には同様の実装がなされています。連想配列も名前からわかるように配列の一種なんですが、前回学んだ配列の添え字は数でした。連想配列は数ではなく文字列を、添え字にしたものです。使い方を覚えれば実にユニークなテキスト処理のツールに成ります。

I 連想配列

実例を示しましょう。

# script 17-1

BEGIN{
	meibutsu["大阪"] = "たこやき"
	meibutsu["名古屋"] = "きしめん"
	meibutsu["福岡"] = "辛子明太子"
	meibutsu["静岡"] = "お茶"
	
	print "大阪の名物は " meibutsu["大阪"]
	print "名古屋の名物は " meibutsu["名古屋"]
	print "福岡の名物は " meibutsu["福岡"]
	print "静岡の名物は " meibutsu["静岡"]
}

Input欄 Null Output欄 Screen で実行してみてください。文字列を添え字として配列が作られているのがわかるでしょう。都市の名前をキーワードにして、それと結びつけて別の文字列を記憶しているわけで、ここから連想配列と呼ばれます。添え字は文字列ですが、連想配列に代入する値は、文字列でなくてもかまいません。数値でも可です。連想配列の添え字([ ]内の文字列です)をキーと呼びます。連想配列の名前は普通の配列の命名法と同じです。ただキーは文字列なので、常に引用符でかこまないといけません。

(注)awkにおいては実は普通の数字を添え字とする配列も、内部的には、連想配列として実装されているということです。awk自体のプログラムソースを検討する暇がないので詳細は不明ですが。

配列名[キー] = 値          # 値は文字列か数値


II 連想配列の使い方

文字列をキーとする配列なので、その使い方は慣れるまで、少し戸惑うかもしれません。いくつか使い方で注意すべき点をのべておきましょう。まず連想配列も配列の一種です。配列というのは同一の名前をもつ変数を、添え字(キー)によって区別するものです。したがって、連想配列の一つ一つはそれぞれ変数として、数値と文字列をその値として持ちます。このことを思い出してください。そしてawkの変数はスクリプト中に記述した時点で存在します。初期値は0と空文字列 ""です。

1) 連想配列への代入

連想配列への代入は普通の変数と同じように代入演算子 = を使います。

# script 17-2

BEGIN{
	 meibutsu["大阪"] = 5
     
	 print "大阪の名物は " meibutsu["大阪"] "個ある"
     
	 meibutsu["大阪"] = meibutsu["大阪"]  + 1
     
	 print "大阪の名物は " meibutsu["大阪"] "個になった"
}

上のスクリプトを実行すると(Input欄 Null Output欄 Screen)

大阪の名物は 5個ある
大阪の名物は 6個になった

という結果がでます。
このスクリプトを普通の変数を使って書くと、下のようになります。全く同じ結果が出力されます。

# script 17-3

BEGIN{
	 x = 5
	 print "大阪の名物は " x "個ある"
	 x = x  + 1
	 print "大阪の名物は " x "個になった"
}

したがって、普通の変数と同じように インクリメント演算子 ++ やデクリメント演算子 -- も 使えます。17-2 の スクリプト3行目

meibutsu["大阪"] = meibutsu["大阪"]  + 1

は、下のようにも書けます。

meibutsu["大阪"]++


2) 連想配列の全ての要素の数え上げ

普通の配列の全ての要素を数え上げるには、for文や while文を使えました。いくつの配列を作ったかを覚えておき、その数を使って、for文やwhile文で回してやればいいんですね。たとえば5つの要素をもつ配列 arr[ ] の全ての要素を表示するには、

for(i = 1; i <= 5; i++)
	print arr[i]

とします。しかし、連想配列は文字列をキーとしていますから、このように、数を添え字としてループするという方法はとれません。連想配列の場合は次のようにします。

for( 仮引数 in 連想配列名)
	     処理

連想配列にいくつのキーを設定したのか、これをawkは覚えていますから、任せてしまえばいいのです。上の式で、仮引数は、変数と同じで、どんな名前でもかまいません。また連想配列名は、連想配列の [ ] を除いたものです。これを使って一番最初の名物のスクリプトを書き換えますと、以下のようになります。

# script 17-4

BEGIN{
	meibutsu["大阪"] = "たこやき"
	meibutsu["名古屋"] = "きしめん"
	meibutsu["福岡"] = "辛子明太子"
	meibutsu["静岡"] = "お茶"
	
 	for( key in meibutsu)                           # key を 仮引数として設定
	{
		print key "の名物は " meibutsu[key]     # 設定した仮引数 key を用いる
	}
}

上のfor文では、awkは覚えているキー( ここでは四つあります )を、一つ一つ変数key に代入しながら、そのキーで指定される連想配列変数の内容を、取り出して、print してくれます。

では、もうひとつ例をあげましょう。
次のような英文があります。ここにでてくる単語全ての出現回数を数え上げるスクリプトです。使うのは、data17.txtで次のような簡単な英文です。連想配列の使い方を示すためのものなので、簡単なものにします。

data17.txt (ダウンロードできます)
This is a book
It is mine
That is a pen
It is yours

上の英文では処理のプロセスを簡単にするため、文末のピリオドは除いてあります。
ではスクリプトです。

# script 17-5

{
	for(i = 1; i <= NF; i++)
		appear[$i]++
}
END{
	for( key in appear)
	{
		print key " : " appear[key]
		n++
	}
	print "計 " n "語"
}

まずこのスクリプトでは、本処理の部分で、入力行の各フィールドの単語をキーとする連想配列をつくります。
例えば、ファイルの第一行目を読んで、for文のループを実行しますが、 i が 1 のときは、下のようになります。

appear[$1]++ 

今、$1 は "this" であるので、これは実際には

appear["this"]++ 

です。この式は複雑なようですが、this をキーとする連想配列の変数がひとつ作られ、その変数の値が、1だけインクリメントされることを意味しています。

x++

と同じことです。appear["this"] が一つの変数だということをしっかり頭に入れておいてください。配列の x[1] や x[2] などがそれぞれ変数であったのと同じことです。

x, y, z, 				#変数

x[1], x[2], x[3]  			# 配列変数

x["this"], x["is"], x["a"] 		# 連想配列変数

そしてこの変数も、作られたときは 0 と "" に初期化されます。そしてインクリメントは数値を加える演算ですから、この変数は数値として扱われ、その値は 0 から 1 にかわります。appear["this"] は 1 という値をもつようになります。
従って、第一行目 ( This is a book ) を読んだときのスクリプトの実行状態を具体的にあらわせば、以下のようになります。

appear["This"]++; appear["is"]++; appear["a"]++; appear["book"]++;

このとき連想配列変数は四つ作られて、それぞれ1という値を持つようになります。次に2行目を読んだときは

appear["It"]++; appear["is"]++; appear["mine"]++;

こうなります。このとき、appear["is"]はすでに作られている変数なので、インクリメントされるだけで、値は2になります。その他は新しく作られて、値は0から1にインクリメントされます。このように、初めてでてくる単語については、それをキーとする連想配列変数が作られインクリメントされ、既出の単語については、値がインクリメントされるだけです。
3行目では、新たに二つ作られて、二つはインクリメントされるだけです。

appear["That"]++; appear["is"]++; appear["a"]++; appear["pen"]++;

4行目では、一つが新しく作られ、二つがインクリメントされるだけです。

appear["It"]++; appear["is"]++; appear["yours"]++;

全部でいくつ連想配列変数がつくられたか分かりますか。覚えてないですよね。それでもかまいません。人間は忘れてもawkは覚えてくれています。全部の連想配列変数について、その値を出力してもらいます。

END{
	for( key in appear)
	{
		print key " : " appear[key]
		n++
	}
	print "計 " n "語"
}

ここで変数 n はひとつのキーを処理するたびに0からインクリメントしますから、キーの数を表すことになります。

多分awkの文法のなかで、この連想配列がもっともややこしいものかも知れません。しかし最も強力なツールであるといっても良いでしょう。上のスクリプトを参考に自分でも色々と実験してマスターしてください。


前回 目次 Home