|
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
}
|