是否可以使用可以接受各种表单的键创建一个python字典?

时间:2018-06-16 01:23:16

标签: python python-2.7 dictionary key

data = (1,1,1,1,1)

dict_letters = {(1,1,1,1,1) : 'A',
                (0,1,1,0,1) : 'B',
                (1,1,1,1,1) : 'C',   
                (1,0,1,0,1) : 'D'}

def search():
            for key in dict_letters:
                if data == key:
                    print(dict_letters[key])

search()

#when running, this would result in only 'C' being printed; 'A' was never printed

以前在我的代码中,我获得了一个由0和1(data元组组成)的唯一5项元组。这5个项目对于区分大多数字母(如“B”和“D”)与我的字典中的其余字母至关重要。但是,当有两个键具有相同的5个项目时,我遇到了一个问题,因此我向元组添加了10个项目(其他识别数据)以帮助进一步区分键;这是我当前词典的摘录:

data = (0,1,1,0,1,1,1,1,1,1,1,1,1,1,1)
data = (0,1,1,0,1,0,0,0,0,0,0,0,0,0,0)
data = (0,1,1,0,1,0,0,1,1,1,0,0,1,0,1)

#x = 0 or 1
dict_letters = {(1,1,1,1,1,x,x,1,x,x,x,x,x,x,x) : 'A',
                (0,1,1,0,1,x,x,x,x,x,x,x,x,x,x) : 'B',
                (1,1,1,1,1,x,x,0,x,x,x,x,x,x,x) : 'C',    
                (1,1,0,0,1,x,x,x,x,x,x,x,x,x,x) : 'D'}

def search():
            for key in dict_letters:
                if data == key:
                    print(dict_letters[key])

search()

#I need to find a way for all of the data tuples to print 'B' after running the program

在这段摘录中,我只为其中一个附加项创建了条件,以区分“A”和“C”。我想知道是否可以忽略其他9个额外的项目是0还是1,因为它们对于区分这两个键无用(我想忽略的项目标有x)。我还想忽略“B”和“D”的10个额外项目,因为前5个项目足以进行识别。例如,我希望将(0,1,1,0,1,0,0,0,0,0,0,0,0,0,0)(0,1,1,0,1,1,1,1,1,1,1,1,1,1,1)(0,1,1,0,1,0,0,1,1,1,0,0,1,0,1)等方式全部读作“B”,而无需为“B”编码2047个额外的键。

我尝试在字典之前设置x = 0 or 1x = 0 and 1,但这些不起作用,因为我发现在运行程序后,键因某种原因设置为(0,1,1,0,1,1,1,1,1,1,1,1,1,1,1)

注意:我正在考虑将来至少使用所有其他项目,因此不能删除任何10个附加项目。

我对Python也比较陌生,所以如果你能让答案尽可能简单,我将不胜感激。提前谢谢!

2 个答案:

答案 0 :(得分:3)

我的理解是,如果某些tuple为关键字,您希望忽略此tuple中的某些条目(如果它们与现有密钥不完全匹配)。

您可以在collections.UserDict和自定义__getitem__方法的帮助下实施类似字典的课程。

以下实现假定tuple中的条目为10。没有这个假设,就必须遍历所有密钥。

from UserDict import UserDict
# for Python 3 use this import instead:
# from collections import UserDict

from itertools import product

class WildcardDict(UserDict):
    def __getitem__(self, args):
        item, *wildcards = args

        try:
            return self.data[item]
        except KeyError:
            for xs in product((0, 1), repeat=len(wildcards)):
                xs = iter(xs)
                item = tuple(next(xs) if i in wildcards else x for i, x in enumerate(item))
                if item in self.data:
                    return self.data[item]
        raise KeyError(args)

d = WildcardDict()

d[0, 1, 1, 0, 1] = 'B'

print(d[(0, 1, 1, 0, 1), ]) # 'B'
print(d[(0, 1, 0, 0, 0), 2, 4]) # 'B'

请注意,dict项目查找通常是 O(1),尽管这使得它 O(2 k 其中 k 是通配符的数量。特别是,这意味着如果通配符的数量一直在增长,那么最好使用list,其中查找将是 O(n)

答案 1 :(得分:3)

我们可以使用普通dict来执行此任务,我们只需为每个字母构建所有可能的键。你的关键元组包含15个项目,每个项目有2个不同的值,因此最多只有2 ** 15 = 32768个不同的模式,这在现代机器上非常小。

我们可以使用itertools.product有效地生成所有模式。 product从您传递的args中有效地创建嵌套的for循环。这是该技术的简短说明。以下代码生成与10XX01对应的所有模式。

from itertools import product

for t in product(*[(1,), (0,), (0, 1), (0, 1), (0,), (1,)]):
    print(t)

<强>输出

(1, 0, 0, 0, 0, 1)
(1, 0, 0, 1, 0, 1)
(1, 0, 1, 0, 0, 1)
(1, 0, 1, 1, 0, 1)

以下是一些代码,它们使用问题中提供的数据来构建可用于搜索的dict。我们使用dict.get方法,这样如果您查找不在dict中的模式,代码将返回None

from __future__ import print_function
from itertools import product

#x = 0 or 1
X = 'x'
letter_patterns = {
    (1, 1, 1, 1, 1, X, X, 1, X, X, X, X, X, X, X): 'A',
    (0, 1, 1, 0, 1, X, X, X, X, X, X, X, X, X, X): 'B',
    (1, 1, 1, 1, 1, X, X, 0, X, X, X, X, X, X, X): 'C',
    (1, 1, 0, 0, 1, X, X, X, X, X, X, X, X, X, X): 'D',
}

def make_dict(letter_patterns):
    ''' Build a dict of all the bit patterns for each letter '''
    xlate = {0: (0,), 1: (1,), X: (0, 1)}
    letter_dict = {}
    # Generate all of the (0, 1) combinations for each X in each pattern
    for pattern, letter in letter_patterns.items():
        for key in product(*[xlate[u] for u in pattern]):
            letter_dict[key] = letter
    return letter_dict

# test

letter_dict = make_dict(letter_patterns)

test_items = [
    ((1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), 'A'),
    ((1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1), 'A'),
    ((1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0), 'A'),
    ((0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), 'B'),
    ((0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 'B'),
    ((0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1), 'B'),
    ((1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 'C'),
    ((1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1), 'C'),
    ((1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), 'C'),
    ((1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 'D'),
    ((1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1), 'D'),
    ((1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), 'D'),
    ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 'Z'),
]

# Check that each test key gets the correct letter, or returns
# None if the key isn't in letter_dict
for key, true_letter in test_items:
    letter = letter_dict.get(key)
    print(key, true_letter, letter, letter == true_letter)

<强>输出

(1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0) A A True
(1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) A A True
(1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0) A A True
(0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) B B True
(0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) B B True
(0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1) B B True
(1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) C C True
(1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1) C C True
(1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0) C C True
(1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) D D True
(1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1) D D True
(1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) D D True
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) Z None False

此代码在Python 2和3上都正确运行(在2.6.6和3.6.0上测试)。您可以通过更改

使Python 2上的效率略高一些
for pattern, letter in letter_patterns.items():

for pattern, letter in letter_patterns.iteritems():

<小时/> letter_patterns中的元组不是很方便,特别是如果你想在letter_patterns中加入很多符号。为了减少键入,而不是使用那些元组,我们可以使用字符串。以上是上述代码的变体。结果letter_dict仍然使用元组键,因为我认为这是您从Leap Motion设备硬件获得的。

letter_patterns = {
    'A': '11111xx1xxxxxxx',
    'B': '01101xxxxxxxxxx',
    'C': '11111xx0xxxxxxx',
    'D': '11001xxxxxxxxxx',
}

def make_dict(letter_patterns):
    ''' Build a dict of all the bit patterns for each letter '''
    xlate = {'0': (0,), '1': (1,), 'x': (0, 1)}
    letter_dict = {}
    # Generate all of the (0, 1) combinations for each X in each pattern
    for letter, pattern in letter_patterns.items():
        for key in product(*[xlate[u] for u in pattern]):
            letter_dict[key] = letter
    return letter_dict