2010-10-28 21 views
6

Estoy tratando de encontrar una estructura de datos tipo diccionario que pueda usar en Erlang. El objetivo es garantizar que todos los valores, así como las claves, sean únicos. Puedo hacerlo con controles de coherencia explícitos después de cada modificación, pero espero que haya un tipo oscuro que haga esto por mí. ¿Hay alguno? Si no es así, ¿hay una mejor manera que poner un cheque en cada función que modifica los datos (o devuelve una copia ligeramente diferente)?Tabla hash bidireccional en Erlang

Espero tener al menos 120 elementos y no más de unos miles, en caso de que eso importe.

Respuesta

6

¿Qué pasa algo así:

-module(unidict). 

-export([ 
    new/0, 
    find/2, 
    store/3 
    ]). 


new() -> 
    dict:new(). 


find(Key, Dict) -> 
    dict:find({key, Key}, Dict). 


store(K, V, Dict) -> 
    Key = {key, K}, 
    case dict:is_key(Key, Dict) of 
     true -> 
      erlang:error(badarg); 
     false -> 
      Value = {value, V}, 
      case dict:is_key(Value, Dict) of 
       true -> 
        erlang:error(badarg); 
       false -> 
        dict:store(Value, K, dict:store(Key, V, Dict)) 
      end 
    end. 

Ejemplo sesión de shell:

1> c(unidict). 
{ok,unidict} 
2> D = unidict:new(). 
{dict,0,16,16,8,80,48, 
     {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}, 
     {{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}} 
3> D1 = unidict:store(key, value, D). 
{dict,2,16,16,8,80,48, 
     {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}, 
     {{[],[],[],[],[],[],[],[],[],[],[],[],[],[], 
     [[{key,key}|value],[{value,...}|{...}]], 
     []}}} 
4> D2 = unidict:store(key, value, D1). 
** exception error: bad argument 
    in function unidict:store/3 
5> D2 = unidict:store(key2, value, D1). 
** exception error: bad argument 
    in function unidict:store/3 
6> D2 = unidict:store(key, value2, D1). 
** exception error: bad argument 
    in function unidict:store/3 
7> D2 = unidict:store(key2, value2, D1). 
{dict,4,16,16,8,80,48, 
     {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}, 
     {{[], 
     [[{key,key2}|value2]], 
     [],[],[],[],[],[],[],[],[],[],[], 
     [[{value,value2}|{key,key2}]], 
     [[{key,key}|value],[{value,...}|{...}]], 
     []}}} 
8> unidict:find(key, D2). 
{ok,value} 
9> unidict:find(key2, D2). 
{ok,value2} 
+0

Me gusta esto, pero ¿hay alguna razón por la que haya usado 'dict: find' en lugar de' dict: is_key'? – nmichaels

+0

Usar 'dict: find' funcionará igual de bien. (No es mi código) – rvirding

+0

Tienes razón dict: is_key puede ser un poco mejor aquí. Pensé en dict: actualiza primero y luego solo prueba dict: find – hdima

1

¿Hay una?

No en la biblioteca estándar, creo. Utilizaría un par que consta de dict() y set() de valores.

1

Se puede utilizar una lista simple {clave, valor} para un par de cientos de elementos:

put(L, K, V) -> 
    case lists:keyfind(K, 1, L) of 
    {K, _} -> erlang:error(badarg); 
    false -> 
     case lists:keyfind(V, 2, L) of 
     {_, V} -> erlang:error(badarg); 
     false -> [{K,V} | L] 
     end 
    end. 

get(L, K) -> 
    case lists:keyfind(K, 1, L) of 
    {K, V} -> {'value', V}; 
    false -> 'undefined' 
    end.