YAYAで連想配列が使えないと聞いたので簡単なのを実装してみた。 どれが速いかわからないので数種類やってみた。
ハッシュ:1つの連想配列メモリを使ってIDで区別する実装(微妙そう)†EVALと巨大な引数渡しを回避する方法 利点†
欠点†
使用例†// map__hash_size = 65536 // 確保するハッシュ領域のサイズ 実行中一度決めたら変更しない _m = map_new() // 初期化してIDを取得 _junk = map_set(_m, 'key', 'value') _k = map_get(_m, 'key') _ks = map_keys(_m) _junk = map_delete(_m, 'key') _junk = map_destroy(_m) // 削除して使えるハッシュ領域を確保 _junk = map_destroy_all() // ハッシュ領域のグローバル変数開放 実装†/* _map_id = map_new() 連想配列初期化 cf. map = {} */ map_new{ if ! ISVAR('map__hash_size') { map__hash_size = 65536 } if ! ISVAR('map__id_num') { map__id_num = 0 } if ! ISVAR('map__key_lists') { map__key_lists = IARRAY } if ! ISVAR('map__keys') { map__keys = IARRAY } if ! ISVAR('map__values') { map__values = IARRAY } map__id_num map__id_num++ } /* _value = map_set(_map_id, _key, _value) 連想配列_map_idの_keyに_valueをセット cf. map{key} = value */ map_set{ _id = _argv[0] _key = _argv[1] _value = _argv[2] _hash = map__get_only_index(_id, _key) // キーが事前に存在しないならmap__key_listsにキー情報を追加 if map__keys[_hash] == IVOID { map__key_lists = (map__key_lists, _id, _key) } map__keys[_hash] = _key map__values[_hash] = _value _value } /* _value = map_get(_map_id, _key) 連想配列_map_idの_keyを参照 cf. value = map{key} */ map_get{ _id = _argv[0] _key = _argv[1] _hash = map__get_only_index(_id, _key) map__values[_hash] } /* _junk = map_delete(_map_id, _key) 連想配列_map_idの_keyを削除 cf. delete(map{key}) */ map_delete{ _id = _argv[0] _key = _argv[1] _hash = map__get_only_index(_id, _key) map__keys[_hash] = IVOID map__values[_hash] = IVOID } /* _keys = map_keys(_map_id, _key) 連想配列_map_idの_keyを列挙 cf. keys = keys(map{key}) */ map_keys{ _id = _argv[0] _size = ARRAYSIZE(map__key_lists) / 2 _keys = IARRAY for _i = 0; _i < _size; _i++ { if map__key_lists[_i * 2] == _id { _key = map__key_lists[_i * 2 + 1] _hash = map__get_only_index(_id, _key) if map__values[_hash] != IVOID { _keys = (_keys, _key) } } } _keys } /* _junk = map_destroy(_map_id) 連想配列_map_idを削除 */ map_destroy{ // keysによりmap__keys, map__values当該を消してからmap__key_lists当該を消す _id = _argv[0] _keys = map_keys(_id) foreach _keys; _key { _hash = map__get_only_index(_id, _key) map__keys[_hash] = IVOID map__values[_hash] = IVOID } _size = ARRAYSIZE(map__key_lists) / 2 _to_delete = IARRAY for _i = 0; _i < _size; _i++ { if map__key_lists[_i * 2] == _id { _to_delete = (_to_delete, _i) } } _to_delete = ASORT('int,descending', _to_delete) foreach _to_delete; _i { map__key_lists[_i * 2, _i * 2 + 1] = IARRAY } } /* _junk = map_destroy_all() 連想配列が使用する変数を削除 */ map_destroy_all{ ERASEVAR('map__hash_size', 'map__id_num', 'map__key_lists', 'map__keys', 'map__values') } map__get_only_index{ // 重複しないようインデックスをずらす _id = _argv[0] _key = _argv[1] _hash_key = _id + TOSTR(_key) _hash = map__hash(_hash_key) while (map__keys[_hash] != IVOID) && (map__keys[_hash] != _key) { if _hash >= (map__hash_size - 1){ _hash = 0 } else { _hash++ } } _hash } map__hash{ // ハッシュ関数 _key = _argv[0] _key_len = STRLEN(_key) _hash = 0 for _i = 1; _i < _key_len; _i++ { _hash = (_hash * 137 + CHRCODE(_key, _i)) % map__hash_size } _hash } ハッシュ:EVALによる実装(あり?)†EVALを使う代わりにより自然なロジックで実装できる。 利点†
欠点†
使用例†// map__hash_size = 2048 // 一連想配列に確保するハッシュ領域のサイズ 実行中一度決めたら変更しない _m = map_new() // 初期化してIDを取得 _junk = map_set(_m, 'key', 'value') _k = map_get(_m, 'key') _ks = map_keys(_m) _junk = map_delete(_m, 'key') _junk = map_destroy(_m) // 変数開放 実装†/* _map_id = map_new() 連想配列初期化 cf. map = {} */ map_new{ if ! ISVAR('map__hash_size') { map__hash_size = 2048 } if ! ISVAR('map__id_num') { map__id_num = 0 } LETTONAME('map__keys_' + map__id_num, IARRAY) LETTONAME('map__values_' + map__id_num, IARRAY) map__id_num map__id_num++ } /* _value = map_set(_map_id, _key, _value) 連想配列_map_idの_keyに_valueをセット cf. map{key} = value */ map_set{ _id = _argv[0] _key = _argv[1] _value = _argv[2] _hash = map__get_only_index(_id, _key) _junk = EVAL('map__keys_' + map__id_num + '[_hash] = _key') _junk = EVAL('map__values_' + map__id_num + '[_hash] = _value') _value } /* _value = map_get(_map_id, _key) 連想配列_map_idの_keyを参照 cf. value = map{key} */ map_get{ _id = _argv[0] _key = _argv[1] _hash = map__get_only_index(_id, _key) EVAL('map__values_' + map__id_num + '[_hash]') } /* _junk = map_delete(_map_id, _key) 連想配列_map_idの_keyを削除 cf. delete(map{key}) */ map_delete{ _id = _argv[0] _key = _argv[1] _hash = map__get_only_index(_id, _key) _junk = EVAL('map__keys_' + map__id_num + '[_hash] = IVOID') _junk = EVAL('map__values_' + map__id_num + '[_hash] = IVOID') } /* _keys = map_keys(_map_id, _key) 連想配列_map_idの_keyを列挙 cf. keys = keys(map{key}) */ map_keys{ _id = _argv[0] _keys = IARRAY _size = EVAL('ARRAYSIZE(map__keys_' + map__id_num + ')') for _i = 0; _i < _size; _i ++ { _key = EVAL('map__keys_' + map__id_num + '[_i]') if _key != IVOID { _keys = (_keys, _key) } } _keys } /* _junk = map_destroy(_map_id) 連想配列_map_idを削除 */ map_destroy{ _id = _argv[0] ERASEVAR('map__keys_' + map__id_num) ERASEVAR('map__values_' + map__id_num) } map__get_only_index{ // 重複しないようインデックスをずらす _id = _argv[0] _key = _argv[1] _hash = map__hash(_key) while (EVAL('map__keys_' + _id + '[_hash]') != IVOID) && (EVAL('map__keys_' + _id + '[_hash]') != _key) { if _hash >= (map__hash_size - 1){ _hash = 0 } else { _hash++ } } _hash } map__hash{ // ハッシュ関数 _key = _argv[0] _key_len = STRLEN(_key) _hash = 0 for _i = 1; _i < _key_len; _i++ { _hash = (_hash * 137 + CHRCODE(_key, _i)) % map__hash_size } _hash } ハッシュ:引数渡しによる実装(おすすめ?)†巨大な引数渡しをする代わりに、自然なロジックと自然な変数のスコープを実現できる。 利点†
欠点†
使用例†// map__hash_size = 2048 // 一連想配列に確保するハッシュ領域のサイズ 実行中一度決めたら変更しない _m = map_new() // 初期化して実体的な連想配列を取得 _m = map_set(_m, 'key', 'value') // 操作後の連想配列は返り値 _k = map_get(_m, 'key') _ks = map_keys(_m) _m = map_delete(_m, 'key') // 変数の開放は特に必要ない 実装†/* _map = map_new() 連想配列初期化 cf. map = {} */ map_new{ if ! ISVAR('map__hash_size') { map__hash_size = 2048 } IARRAY } /* _map = map_set(_map, _key, _value) 連想配列_mapの_keyに_valueをセットした連想配列を返す cf. map{key} = value */ map_set{ _key = _argv[_argc - 2] _value = _argv[_argc - 1] _argv[_argc - 2, _argc - 1] = IARRAY _hash = map__get_only_index(_argv, _key) _argv[_hash * 2] = _key _argv[_hash * 2 + 1] = _value _argv } /* _value = map_get(_map, _key) 連想配列_mapの_keyを参照 cf. value = map{key} */ map_get{ _key = _argv[_argc - 1] _argv[_argc - 1] = IARRAY _hash = map__get_only_index(_argv, _key) _argv[_hash * 2 + 1] } /* _map = map_delete(_map, _key) 連想配列_mapの_keyを削除した連想配列を返す cf. delete(map{key}) */ map_delete{ _key = _argv[_argc - 1] _argv[_argc - 1] = IARRAY _hash = map__get_only_index(_argv, _key) _argv[_hash * 2] = IVOID _argv[_hash * 2 + 1] = _IVOID _argv } /* _keys = map_keys(_map, _key) 連想配列_mapの_keyを列挙 cf. keys = keys(map{key}) */ map_keys{ _keys = IARRAY for _i = 0; _i < _argc / 2; _i ++ { _key = _argv[_i * 2] if _key != IVOID { _keys = (_keys, _key) } } _keys } map__get_only_index{ // 重複しないようインデックスをずらす _key = _argv[_argc - 1] _argv[_argc - 1] = IARRAY _hash = map__hash(_key) while (_argv[_hash * 2] != IVOID) && (_argv[_hash * 2] != _key) { if _hash >= (map__hash_size - 1){ _hash = 0 } else { _hash++ } } _hash } map__hash{ // ハッシュ関数 _key = _argv[0] _key_len = STRLEN(_key) _hash = 0 for _i = 1; _i < _key_len; _i++ { _hash = (_hash * 137 + CHRCODE(_key, _i)) % map__hash_size } _hash } |