配列と連想配列
「配列」とは、インデックスが数字であるものを称し、「連想配列」とはインデックスが文字列であるものを指します。他の言語であれば、連想配列はハッシュや辞書と呼ばれますが、AWK界隈では連想配列と呼ばれています。配列の役目は「○○番目のものが○○である」という指定を行うことです。したがって、次のようにApple、Orange、Bananaというデータに対し、この通りの順番で番号を割り振るような場合に配列を用います。配列であることを明確に示すために配列名に複数形を使うと分かりやすいでしょう。
BEGIN { names[1] = "Apple"; names[2] = "Orange"; names[3] = "Banana"; }
もちろん、次のように変数で書くこともできます。
BEGIN { name1 = "Apple"; name2 = "Orange"; name3 = "Banana"; }
しかし、変数の場合には後で呼び出すような場面で大変になります。一方、配列に入れることでfor文やwhile文で呼び出すことができます。
BEGIN { names[1] = "Apple"; names[2] = "Orange"; names[3] = "Banana"; for (i = 1; i <= 3; i++) { print i, names[i]; } }
このように配列に入れておくと、いろいろと便利なことがあります。
さて、配列の個数を自動的に取得する方法はないのでしょうか? 上記の場合は「3」と決め打ちになっています。配列の個数を取得するにはlength関数を使います。
BEGIN { names[1] = "Apple"; names[2] = "Orange"; names[3] = "Banana"; for (i = 1; i <= length(names); i++) { print i, names[i]; } }
このlength関数は少し特殊で、引数がない場合には$0の文字数を返し、引数が変数の場合には変数の長さを返します。引数が配列である場合には、配列の個数を返します。このようにlength関数はちょっとトリッキーな関数です。一部のAWKではバグが残っていて、うまく動作しないこともあります。
次に連想配列ですが、連想配列は「○○の○○」というイメージになります。例えば、人の身長や果物の値段などが該当します。したがって、連想配列の名前は「***_of」のようにすると分かりやすいでしょう。
BEGIN { value_of["Apple"] = 100; value_of["Orange"] = 200; value_of["Banana"] = 300; }
この連想配列を取得するには、「for ~ in」というfor文で連想配列専用の方法を用います。
BEGIN { value_of["Apple"] = 100; value_of["Orange"] = 200; value_of["Banana"] = 300; for (i in value_of) { print i, value_of[i]; } }
連想配列として呼び出しているので、出力される順序は何かでソートされているわけではありません。他の言語において、連想配列はハッシュと呼ばれるように、ハッシュテーブルを呼び出しているに過ぎないからです。もし、結果をソートする必要がある場合にはGNU AWKの拡張を用いるか、自前でソートするための関数を準備する必要があります。
普段、他の言語を用いている方には配列と連想配列が一緒であるというのは不思議に感じられるかもしれませんが、これは「AWKには変数の型がない」という仕様に起因するものです。したがって、配列においてはインデックスを数値で扱いましたが、文字列でも構わないのです。
BEGIN { names["1"] = "Apple"; names["2"] = "Orange"; names["3"] = "Banana"; }
さて、この配列と連想配列ですが、AWKでは同じ連想配列です。つまり、配列の中身を連想配列として「for ~ in」で取得できます。
BEGIN { names[1] = "Apple"; names[2] = "Orange"; names[3] = "Banana"; for (i in names) { print i, names[i]; } }
前述のように、length関数にバグがあって配列の個数を取得できない場合には、次のようにする必要があります。
BEGIN { names[1] = "Apple"; names[2] = "Orange"; names[3] = "Banana"; for (i in names) { num_names++; } print num_names; }
リストがない
このようにすべてが連想配列であるということは、順番を付けるリストというものがAWKには存在しない、ということです。とはいえ、毎回1つずつ定義するのは面倒ですよね。そこで、split関数を用います。
BEGIN { fruit_list = "Apple Orange Banana"; num_fruits = split(fruit_list, fruits); for (i = 1; i <= num_fruits; i++) { print i, fruits[i]; } }
split関数は第1引数の文字列を第3引数の正規表現(第3引数がない場合には組込変数FS)で分割し、第2引数の名前を持つ配列に格納します。また、戻り値は配列の数になります。このようにすることで、疑似的にリストのようなものを作ることができます。