Two-way Hash Table in Erlang
I'm trying to come up with a dictionary-like data structure that I can use in Erlang. The goal is to guarantee that all the values, as well as the keys, are unique. I can do it with explicit consistency checks after every modification, but I'm hoping there's an obscure type that does this for me. Is there one? If not, is there a better way than wrapping a chec开发者_StackOverflow社区k into every function that modifies the data (or returns a slightly different copy)?
I'm expecting to have at least 120 elements and no more than a few thousand, in case that matters.
What about something like that:
-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.
Example shell session:
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}
Is there one?
Not in the standard library, I believe. I would use a pair consisting of a dict() and a set() of values.
You can use a simple {key, value} list for a couple of hundred elements:
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.
 
         加载中,请稍侯......
 加载中,请稍侯......
      
精彩评论