Dictionary bidirectional

K

Kless

I need a dictionary where get the result from a 'key' (on left), but
also from a 'value' (on right), how to get it?

I know that dictionaries aren't bidirectional, but is there any way
without use two dictionaries?


Thanks in advance!
 
W

WDC

I need a dictionary where get the result from a 'key' (on left), but
also from a 'value' (on right), how to get it?

I know that dictionaries aren't bidirectional, but is there any way
without use two dictionaries?

Thanks in advance!

You want to print the key as well as the value?
 
B

bearophileHUGS

bukzor:
You need to use two dictionaries. Here's a class that someone's
written that wraps it up into a single dict-like object for you:
http://www.faqts.com/knowledge_base/view.phtml/aid/4376

It contains code like:

try:
del self.data[item]
except KeyError:
pass

Exceptions are useful in python, but with dictionaries this is
probably faster (and shorter), even if it may perform two lookups:

if item in self.data:
del self.data[item]

Bye,
bearophile
 
B

bukzor

It contains code like:
try:
del self.data[item]
except KeyError:
pass
Exceptions are useful in python, but with dictionaries this is
probably faster (and shorter), even if it may perform two lookups:
if item in self.data:
del self.data[item]
Bye,
bearophile

The only case where it would be faster would be if most of the keys were NOT in
the dictionary (rather odd use case). Otherwise I believe you will find the
first way quicker as the exceptions are infrequent.

-Larry

/agree
 
K

Ken Starks

Dennis said:
Just out of curiosity... What do you expect to have returned from...

aDict = { "one" : "two",
"three" : "four",
"What?" : "two" }

when looking for the value "two"?

In a dictionary, the /keys/ are unique... but the /values/ can be
duplicates.

I wonder if anyone has implemented an 'equivalence class' class (for
finite sets) based on this.

Obviously the relation defined by
k1~k2 iff D[k1] == D[k2]
does partition the set of all keys as an equivalence class.

So ... as a kind of inverse you could return a set, a subset of the
keys. How you would get a canonical representative of that set is
a different matter, of course. Unless, as in the OP's case, it is
a singleton set.

It would seem more efficient to do this when a key-value pair is
added or removed from the original dictionary rather than iterating
over all the keys each time you used it.
 
B

bearophileHUGS

Larry Bates:
The only case where it would be faster would be if most of the keys were NOT in
the dictionary (rather odd use case). Otherwise I believe you will find the
first way quicker as the exceptions are infrequent.

I have written a small benchmark:

from random import shuffle

def test1(data, to_delete):
for item in to_delete:
try:
del data[item]
except KeyError:
pass

def test2(data, to_delete):
for item in to_delete:
if item in data:
del data[item]

N = 1000000
M = 2 * N

data = dict.fromkeys(xrange(N), 0)
to_delete = range(M)
shuffle(to_delete)

from timeit import default_timer as clock
t = clock()
#test1(data, to_delete) # 2.4 s
test2(data, to_delete) # 0.8 s
print round(clock() - t, 2), "s"

It creates a dictionary of the first million integers, and then tries
to delete the first two million of integers. So about 1/2 numbers are
present to be deleted. In this situation the version with the try-
except seems about 3 times slower than the other.

Bye,
bearophile
 
K

Kless

Akathorn Greyhat sent me by email the next solution, which althought
isn't generic it works well:

-------------
You could make your own class for that, maybe something like


#########

class MyCoolDictionary(dict):
def __init__(self, *args, **kargs):
dict.__init__(self, *args, **kargs)

def __getitem__(self, item):
try:
return dict.__getitem__(self, item)

except KeyError:
keys=[]
for i in dictio.keys():
if dictio==item:
keys.append(i)
return keys

dictio=MyCoolDictionary({"a" : 1, "b" : 2, "c" : 2})
print dictio["a"]
print dictio["b"]
print dictio[1]
print dictio[2]
#########

The output of this code is:
1
2
['a']
['c', 'b']

Note that it isn't finish, maybe you'll need to make some kind of test
before adding a new value because with this code one value can have
multiple keys, and I have fixed it by returning a list of keys instead
a single value. It's up to you =)

I'm sorry of my poor english =(

Regards,
Akathorn Greyhat
-------------
 
I

Impotent Verse

If keys and values are unique you could do this...

--------------

# Left : Right
roman = { "One" : "I",
"Two" : "II",
"Three" : "III",
"Four" : "IV",
"Five" : "V",
"Six" : "VI",
"Seven" : "VII",
"Eight" : "VIII",
"Nine" : "IX",
"Ten" : "X" }

left, right = zip( *roman.items() )
left = list(left)
right = list(right)

print left[ right.index("VIII") ]

--------------

.... result is "Eight".

Hmmm! zip returns tuples, which need to be turned into lists to do
much with. Maybe not the best solution in this case.

Verse.
 
G

Gerry

If keys and values are unique, maybe just store both in the same
dictionary:

mydict[a] = b
mydict = a

...

Gerry
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top