zshでは連想配列が使える。でも、普通のプログラム言語と違ってちょっと癖があるので、ここで使い方についてまとめてみる。
宣言
連想配列は必ずtypesetかlocalで宣言が必要になる。typeset -A
またはlocal -A
という形で宣言する。
# ローカル変数として宣言する
local -A hash1
# または
typeset -A hash2
# グローバル変数として宣言する
typeset -g -A hash1
連想配列に限らないことだけど、関数の中でtypesetで宣言した場合は関数内のローカル変数になる。typesetで宣言しつつグローバル変数にしたい場合は-gオプションを付ける。
代入
連想配列全体に値を代入するには、カッコでくくって、「キー」「値」の順にスペース区切りで並べて書く。
typeset -A user1
user1=(id 13 name mollifier address Kobe)
# { id => 13, name => mollifier, address => Kobe } という連想配列になる
# カッコだけ書くと空の連想配列になる
typeset -A empty_hash
empty_hash=()
要素の参照
連想配列の各要素を参照する方法はこんな感じ。
typeset -A user1
user1=(id 13 name mollifier address Kobe)
echo $user1[id] #=> 13
echo $user1[name] #=> mollifier
# {}で囲っても良い
echo ${user1[address]} #=> Kobe
要素全体を参照する方法は以下。
# [@]または[*] で値全体の配列になる
echo $user1[@] #=> Kobe 13 mollifier
echo $user1[*] #=> Kobe 13 mollifier
# [@]と[*]は"で囲んだときに違いが出る
# [@]は各要素がそれぞれ"で囲まれる
# [*]は要素全体が"で囲まれて一つの文字列になる(echoでは違いがわからないけど)
echo "$user1[@]" #=> "Kobe" "13" "mollifier"
echo "$user1[*]" #=> "Kobe 13 mollifier"
# $user1[*]は省略して$user1と書ける
echo $user1 #=> Kobe 13 mollifier
# (k)を付けると、すべてのキーを含む配列になる
echo ${(k)user1} #=> address id name
# (kv)を付けると、キー、値、と順に並べた配列になる
echo ${(kv)user1} #=> address Kobe id 13 name mollifier
# 要素数(キー/値の組の数)も取得できる
echo ${#user1} #=> 3
追加、変更、削除
キーを指定して値の追加、変更、削除ができる。
typeset -A user1
user1=(id 13 name mollifier address Kobe)
# この時点では { id => 13, name => mollifier, address => Kobe }
# 追加
user1[age]=17
# この時点 { id => 13, name => mollifier, address => Kobe, age => 17 } になる
# 変更
# すでに存在するキーに対して値を代入すると、値の変更になる
user1[age]=27
# この時点 { id => 13, name => mollifier, address => Kobe, age => 27 } になる
# 要素の削除("で囲む必要があることに注意)
unset "user1[address]"
# この時点 { id => 13, name => mollifier, age => 27 } になる
ループ
ループしたいときは、${(k)連想配列名}
のかたちですべてのキーを取り出してそれでループする。
typeset -A user1
user1=(id 13 'super name' 'super mollifier' address Kobe)
for key in ${(k)user1}; do
echo "$key => $user1[$key]"
done
# 出力
# super name => super mollifier
# address => Kobe
# id => 13
#
# キーや値に空白が入っていても大丈夫
キーを持つかどうかのチェック
${連想配列名[(i)キー名]}
という形で、「キー名」にマッチするキーが文字列として取得できる。もしキーが見つからなかったら空文字列になる。これで、連想配列に特定のキーが含まれているかどうかがチェックできる(他の言語でいうところのhas_keyのようなやつ)。
typeset -A user1
user1=(id 13 name mollifier empty '' address Kobe)
# 指定したキーが含まれる場合
if [[ -n "${user1[(i)id]}" ]]; then
echo "user1 has id"
else
echo "user1 doesn't have id"
fi
#=> user1 has id
# 指定したキーが含まれない場合
if [[ -n "${user1[(i)hoge]}" ]]; then
echo "user1 has hoge"
else
echo "user1 doesn't have hoge"
fi
#=> user1 doesn't have hoge
# 値が空文字列でもキーが存在するかどうかがチェックできる
if [[ -n "${user1[(i)empty]}" ]]; then
echo "user1 has empty"
else
echo "user1 doesn't have empty"
fi
#=> user1 has empty
この(i)
は、代わりに(I)
と書いても同じ意味になる。
こんな感じでzshの連想配列が使えるので、試してみてください!