Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

partial match dictionary key(of tuples) in python

I have a dictionary that maps 3tuple to 3tuple where key-tuples have some element in common

dict= { (a,b,c):(1,2,3),
        (a,b,d):tuple1,
        (a,e,b):tuple,
        .
        (f,g,h):tuple3,
        .
        .
        .
        tuple:tuple
      }

now how can I find the values that match to (a,b,anyX) in a dictionary ie (1:2:3) and tuple1

this is computer generated and very large thus, it takes effort to determine anyX.

so, any good ways I can do this?

edit:partial matching of (f,g,*),(f, *,g) to tuple3 will also be helpful but not necessary.

like image 516
Aavaas Avatar asked Sep 19 '13 11:09

Aavaas


People also ask

Can tuple be used as dictionary key in Python?

A tuple can never be used as a key in a dictionary.

How do you access tuples in a dictionary?

Because tuples are hashable and lists are not, if we want to create a composite key to use in a dictionary we must use a tuple as the key. Write code to create a dictionary called 'd1', and in it give the tuple (1, 'a') a value of “tuple”.

Can dictionary have same keys with different values?

Duplicate keys are not allowed. A dictionary maps each key to a corresponding value, so it doesn't make sense to map a particular key more than once.

Can one key have multiple values in dictionary python?

General Idea: In Python, if we want a dictionary to have multiple values for a single key, we need to store these values in their own container within the dictionary. To do so, we need to use a container as a value and add our multiple values to that container.


3 Answers

Lets say if you're passing None for the missing keys then you can use all and zip:

>>> from itertools import permutations
>>> import random
#create a sample dict
>>> dic = {k:random.randint(1, 1000) for k in permutations('abcde', 3)}
def partial_match(key, d):
    for k, v in d.iteritems():
        if all(k1 == k2 or k2 is None  for k1, k2 in zip(k, key)):
            yield v
...         
>>> list(partial_match(('a', 'b', None), dic))
[541, 470, 734]
>>> list(partial_match(('a', None, 'b'), dic))
[460, 966, 45]
#Answer check
>>> [dic[('a', 'b', x)] for x in 'cde']
[541, 734, 470]
>>> [dic[('a', x, 'b')] for x in 'cde']
[966, 460, 45]
like image 98
Ashwini Chaudhary Avatar answered Oct 16 '22 05:10

Ashwini Chaudhary


You could reconstruct your dictionary into a triply nested dict.

dict= { ("foo", 4 , "q"): 9,
        ("foo", 4 , "r"): 8,
        ("foo", 8 , "s"): 7,
        ("bar", 15, "t"): 6,
        ("bar", 16, "u"): 5,
        ("baz", 23, "v"): 4
      }

d = {}
for (a,b,c), value in dict.iteritems():
    if a not in d:
        d[a] = {}
    if b not in d[a]:
        d[a][b] = {}
    d[a][b][c] = value

Here, d is equivalent to:

d = {
    "foo": {
        4:{
            "q": 9,
            "r": 8
        },
        8:{
            "s": 7
        }
    },
    "bar":{
        15:{
            "t": 6
        }
        16:{
            "u": 5
        }
    },
    "baz":{
        23{
            "v": 4
        }
    }
}

Now you can easily iterate through the possible third keys, given the first and second.

#find all keys whose first two elements are "foo" and 4
a = "foo"
b = 4
for c in d[a][b].iterkeys():
    print c

Result:

q
r

This only works for matching the third key. For instance, you wouldn't be able to find all second keys, given the third and the first.

like image 22
Kevin Avatar answered Oct 16 '22 05:10

Kevin


There might be other ways, but assuming you just need to do a single search (in other words there might be ways to build better data structures for repeated searching): (Note that this handles arbitrary lengthed tuple's with the '*' in multiple possible locations)

def match(tup,target):
   if len(tup) != len(target):
      return False
   for i in xrange(len(tup)):
      if target[i] != "*" and tup[i] != target[i]:
         return False
   return True

def get_tuples(mydict,target):
   keys = filter(lambda x: match(x,target),mydict.keys())
   return [mydict[key] for key in keys]

#example:
dict= { (1,3,5):(1,2,3),
        (1,3,6):(1,5,7),
        (1,2,5):(1,4,5),
       }
print get_tuples(dict,(1,3,'*'))

.

like image 35
Foon Avatar answered Oct 16 '22 06:10

Foon