11

我有一个将 3tuple 映射到 3tuple 的字典,其中键元组有一些共同的元素

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

现在如何在字典中找到与 (a,b, anyX )匹配的值ie (1:2:3) and tuple1

这是计算机生成的并且非常大,因此需要努力确定 anyX。

那么,有什么好的方法可以做到这一点吗?

编辑: (f,g,*),(f, *,g) 到 tuple3 的部分匹配也会有所帮助,但不是必需的。

4

4 回答 4

11

假设您要传递None丢失的键,那么您可以使用alland 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]
于 2013-09-19T12:01:09.877 回答
4

您可以将您的字典重建为一个三重嵌套的字典。

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

这里,d等价于:

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

现在,您可以轻松地遍历可能的第三个键,给定第一个和第二个。

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

结果:

q
r

这仅适用于匹配第三个键。例如,给定第三个和第一个,您将无法找到所有第二个键。

于 2013-09-19T12:08:01.430 回答
1

可能还有其他方法,但假设您只需要进行一次搜索(换句话说,可能有一些方法可以为重复搜索构建更好的数据结构):(请注意,这可以在多个可能的情况下处理带有 '*' 的任意长度的元组地点)

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,'*'))

.

于 2013-09-19T12:00:16.883 回答
1

@AshwiniChaudhary 的解决方案可以很容易地适应面向对象的解决方案。您可以子类化dict并添加一个方法:

class tup_dict(dict):
    def getitems_fromtup(self, key):
        for k, v in self.items():
            if all(k1 == k2 or k2 is None for k1, k2 in zip(k, key)):
                yield v

d = tup_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})

res = list(d.getitems_fromtup(("foo", 4, None)))  # [9, 8]
于 2018-11-26T09:40:33.127 回答