I am sure one can come with other ways, custom hashtables, etcâŠ
But given standard practice is to use 2, I donât think any of possibilities offer much beyond additional complexity. If you find anything interesting, please share.
Ideally. If keys + values are distinct then you could store the reverse mapping in the same directory, but I tend not to:
vals = 'ABCDEFGHIJ'
keys = list(range(len(vals)))
# I do this
kvdict = {k: v for k, v in zip(keys, vals)}
vkdict = {v: k for k, v in zip(keys, vals)}
# I suppose one could use this:
bidict = {}
for k, v in zip(keys, vals):
bidict[k] = v
bidict[v] = k
Thanks for the replies. Iâm not thinking about a Python implementation. In Python, I think you need two dicts necessarily. But in CPython? Can one hashtable be used safely to store both keys and values?
You can think of Python code as pseudocode. It largely applies to everything that can be done in CPython.
In CPython dict usage is pretty much the same.
There are some paths to go deeper, but that would be a rabbit hole and large amount of work with most likely little value. (Have a look at dict implementation to have a sense of work it would need to implement something custom without re-using existing dict).
Q: What is the rationale for not allowing duplicate values in bijective mappings? Usually a new item overwrites the previous one. (I understand that the key previously associated with the value must be removed)
What is the rationale for not allowing duplicate values in bijective mappings
If you have an implementation based on two dicts, you donât want have the key->val dict containing key1->VAL and key2->VAL while the other contains VAL->key1 or (exclusively) VAL->key2.
Now, OOP-wise, I think a bidict should expose a âreadâ view in terms of âvalue to keyâ and a âread-writeâ interface for âkey to valueâ. In other words, you should not be able to insert a new entry using its value. Sorry for being unclear when I said âno duplicated valuesâ.
One reason is: what would x.keys() be after a call x[k] = v? is v the key or is it k? For instance if we consider the loggingLevels example, using loggingLevels[name] = value and then loggingLevels.keys() should yield the level names, but not the values. If we were to allow values to be mapped to keys, then this would be via a separate method.
I wouldnât mind this separate method but for a first iteration, Iâd prefer sticking with something simple. Unfortunately, we rejected adding a recipe so I think users will need to use 3rd-party libs.
Thanks for the link. Well, a duplicate value error is what most people here want and expect. The implication is that updating requires special attention. Imagine bi = bidict(a=1, b=2, ...) that should be modified to bidict(a=2, b=1, ...).
bi['a'] = 2 # error (clash with 'b':2)
bi.reverse[2] = 'a' # error (clash with 1:'a')
The linked article shows a forced update, etc. but the added complexity and again several options how to deal with it persuaded me that the proper place for a bi-dictionary implementation is a separate module in PyPi.
A frozen bidict - which does not have any problems with duplicities and updates - is still quite a helpful data structure. But we have that as stated immediately at the discussionâs beginning:
Iâd guess delete operations in the many to many case would need some thought?
In the wikipedia example of the many-to-many, bidirectional mapping between books and authors, you can add books with many authors and authors with many books. On deleting books, you could update Authors to eventually have no books. You could then delete the author, but you would also loose the information that they are an Author. I guess if you are allowed to add books with no authors and Authors without books then you need to be able to keep Authors without books on deletion of their last book, and vice-versa. You would presumably be able to add Authors to existing books and books to existing Authors, incrementally too?
I donât need it now, so Iâve no code. But it is interestingâŠ