import os import json class BiDict(dict): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.inverse = {} for key, value in self.items(): self.inverse.setdefault(value,key) def __setitem__(self, key, value): if key in self : del self.inverse[self[key]] super().__setitem__(key, value) self.inverse.setdefault(value,key) def __delitem__(self, key): value = self[key] if value in self.inverse : del self.inverse[value] super().__delitem__(key) def pop(self,key): value = super().pop(key) self.inverse.pop(value) return value def load(self, path, name): assert os.path.isdir(path), f'dir: {path} does not exists' full = f'{path}/{name}' with open(full,'r') as fh : self.__init__(json.load(fh)) def save(self, path, name): assert os.path.isdir(path), f'dir: {path} does not exists' full = f'{path}/{name}' with open(full,'w') as fh : json.dump(self, fh, sort_keys=True, indent=2) class AttrBiDict(BiDict): def __init__(self, *args, **kwargs): super(AttrBiDict, self).__init__(*args, **kwargs) self.__dict__ = self def __hash__(self): return hash(str(self)) def __eq__(self,other): return self.__hash__() == other.__hash__()
dict
Autovivify in Python
Autovivify is simply fancy word for the behavior of creating a dictionary key-value automatically the moment an element is accessed. Python throws an error if the kv-pair was not already created.
Perl hashes/dictionaries are auto-vivified by default, not so for Python, which could be annoying, because you have to do additional checks thus breaking the normal flow of coding.
Here is how you make a auto vivifying Python dictionary and at the same time quick way to create a Tree structure :
from collections import defaultdict from pprint import pprint def Tree(): return defaultdict(Tree) tree = Tree() tree['mammal']['ape']['chimp'] = 'bobo' pprint(tree,indent=2,compact=True) ----- defaultdict(..., { 'mammal': defaultdict(..., { 'ape': defaultdict(..., { 'chimp': 'bobo'})})})
Even better, if you want cleaner print :
from collections import defaultdict from pprint import pprint def Tree(): return DD(Tree) class DD(defaultdict): __repr__ = dict.__repr__ tree = Tree() tree['mammal']['ape']['chimp'] = 'bobo' pprint(tree,indent=2,compact=True) ------ {'mammal': {'ape': {'chimp': 'bobo'}}}
HashList for key:value pairs
In Prolog if you need to use hashes you can use Dicts, but for small number of kv-pairs it is overkill.
In such cases use the HashList that I invented ;). It is very easy and you can use it as a Two way hash too. Very handy.
% HashList utils : [ key1:val1, key2:val2, ... ], also can be used as TwoWaysHash
keys(HL,Res) :- maplist(\I^K^(I = K:_),HL,Res).
vals(HL,Res) :- maplist(\I^V^(I = _:V),HL,Res).
val(Key,HL,Res) :- member(Key:Res,HL).
key(Val,HL,Res) :- member(Res:Val,HL).
-----
?- use_module(library(lambda)).
?- H = [first:john, last:doe, city:huston, state:tx],
keys(H,Keys),vals(H,Vals),
val(city,H,Val),key(huston,H,Key).
H = [first:john, last:doe, city:huston, state:tx],
Keys = [first, last, city, state],
Vals = [john, doe, huston, tx],
Val = huston,
Key = city .