コンテンツにスキップ

ハッシュ(Tc600-3以降)

Tc600-3 以降では、値の型にハッシュ(連想配列)が加わった。

ハッシュの値やキーには、配列やハッシュを入れられる(入れ子)。入れ子の読み書きや多次元代入は 値の入れ子と多次元代入 を参照。

500 系からの互換性に関わる変更は 600 での変更点 を参照。

生成

ハッシュは IHASH で作る。キーと値を交互に並べる。IHASH() は空のハッシュになる。

_h = IHASH("name", "さくら", "age", 16)
_e = IHASH()

文字列から作るときは HASH_SPLIT を使う。

_h = HASH_SPLIT("a=1,b=2", ",", "=")

ハッシュの変数は、IHASH などで最初にハッシュとして作っておく必要がある。未定義の変数に _x["a"] = 1 と書いても、ハッシュではなく汎用配列の扱いになる("a" は数値として 0 番目と解釈される)。

要素の参照・代入

h[キー] で値を読み、h[キー] = 値 で追加・上書きする。

_h = IHASH()
_h["name"] = "さくら"
_h["name"]       // "さくら"
_h["none"]       // VOID (キーが無いときは未定義の変数と同じ)
_h["age"] += 1   // 複合代入も使える
  • キーが無いときは、未定義の変数と同じく VOID を返す(Tc603-1以降。Tc602-13 までは空文字列だった)。文字列としては空文字列、数値としては 0 として扱われるので、_h["none"] == "" は 1、_h["none"] + 1 は整数の 1 になる(範囲外の要素)
  • 複合代入(+= -= *= /= %=)の左辺のキーが無いときも VOID として計算する(Tc602-10以降)。_count[_name] += 1 で数を数えられる。キーがあって値が空文字列のときは、これまでどおり空文字列として計算する("" + 1 は "1")
  • 「キーが無い」と「値が空文字列や VOID」を区別するときは HASH_EXIST を使う
  • 値には配列やハッシュも入れられる(入れ子)
  • 序数の2番目以降(範囲指定やデリミタ)は無視される。範囲つきの読み出し h[a, b] は空文字列になる

キーの一致

スカラーのキーは「数値」と「文字列」に分けて比べる。

  • 数値として扱うもの: 整数、実数、正規形の整数を表す文字列("9"、"-3" など)
    • "09"、"-0"、"+1"、" 1"、64bit に収まらない数字列は文字列として扱う
  • 数値同士は値で比べる。整数と実数も誤差なく比べる
  • 文字列同士は文字列として比べる。VOID は空文字列と同じキーになる

このため、h[1]、h["1"]、h[1.0] はすべて同じキーになる。一方、h[1.5] と h["1.5"]、h[0] と h["-0"] は別のキーになる。

同じキーとみなされる値を複数回 IHASH に渡したときは、最初のキーと値が残る。

IHASH(9, "i9", "9", "s9")   // 9=i9 だけ

並び順

ハッシュの要素はキーの順に並ぶ。挿入した順ではない。HASH_KEYS、HASH_VALUES、文字列化、foreach、セーブファイルの並びはすべてこの順になる。

  • 数値 < 文字列 の順に並ぶ。数値同士は値の順、文字列同士は文字列の順
  • キーが配列やハッシュのときは、スカラー < 配列 < ハッシュ の順に並び、配列同士・ハッシュ同士は先頭の要素から順に比べる
_h = IHASH(10,1, 9,1, 100,1, -1,1, "b",1, "B",1, 2.5,1)
HASH_KEYS(_h)   // -1,2.5,9,10,100,B,b

値としての振る舞い

操作 結果
真偽 要素が1つ以上あれば真、空なら偽
GETTYPE / GETTYPEEX 5
文字列化(TOSTR や文字列との連結) キー=値 を , でつないだもの。例 a=1,b=x
数値化 0
h1 == h2 要素数、キー、値がすべて一致すれば真。値が入れ子なら中身まで比べる
ハッシュとハッシュ以外の == 常に偽(文字列化した結果が同じでも偽)
+(相手がスカラーかハッシュ) 両方を文字列にして連結する
+(相手が配列) 配列の要素ごとに、ハッシュと文字列として連結する
- * / % 警告 W0024 を出す(下記)
_h = IHASH("a", 1)
_h + 1        // "a=11"
'z' + _h      // "za=1"
_h + _h       // "a=1a=1"
(1,2) + _h    // ("1a=1","2a=1")

- * / %(複合代入を含む)の両辺のどちらかがハッシュのときは、警告 W0024 を出す。結果は、相手がスカラーなら右辺がそのまま返り(h - 1 は 1、1 * h は h)、相手が配列なら要素ごとに計算される。意味のある結果にはならないので使わないこと。なお、配列の要素がハッシュの場合((h, 1) - 1)は W0024 は出ない。

関数の引数と , 演算子

汎用配列は引数や , 演算子で展開されるが、ハッシュは展開されず、そのまま1つの要素になる。

_a = (0, _h, 2)   // 要素数 3。_a[1] はハッシュ
func(_h)          // func の中で _argv[0] がハッシュになる

foreach

ハッシュも foreach で回せる。1変数の形では、値がキーの順に入る。

_h = IHASH("a", 1, "b", 2)
foreach _h ; _v
{
  // _v = 1, 2
}

変数を2つ書くと、1つ目にキー、2つ目に値が入る。この形は配列と簡易配列でも使え、1つ目には 0 から始まるインデックスが入る。

foreach _h ; _k, _v { _s += _k + '=' + _v + ' ' }   // "a=1 b=2 "
foreach ("p", "q") ; _i, _v { ... }                  // _i = 0, 1
foreach "x,y" ; _i, _v { ... }                       // 簡易配列も同じ

詳細は フロー制御 を参照。

関連