从字典的列表中查找一个元素和 return 该键

Find an element from a list in a dictionary and return that key

如果我将 someDictionary 定义为

{'1': 33, '2': 44, '3': 55, '4': 10, '5': 66, '6': 60}

someList定义为

[51, 52, 53, 54, 55, 56]

如何在 someDictionary 中找到与 someList 中的元素相匹配的键?现在,我假设不会超过一场比赛。

我认为它会是这样的:

for k, v in someDictionary.items():
    if v == someList:
        myAnswer = k

鉴于上面的代码,myAnswer 将是 3

我需要做的第二部分是,如果 someList 不包含 someDictionary 中的元素,则找到 someDictionary 中大于(但最接近)最后一个元素的值一些列表 someList[-1]

在那种情况下,myAnswer 将是 6

第一部分,在列表中查找具有字典值的键列表。

someDictionary = {'1': 33, '2': 44, '3': 55, '4': 10, '5': 66, '6': 60}
someList = [51, 52, 53, 54, 55, 56]

res = [key for key, value in someDictionary.items() if value in someList]

第二部分,如果第一部分没有结果,找到最接近的较大值的键(继续):

if not res:
    res = min ([(value, key) for key, value in someDictionary.items() if value > max(someList) ])[1]
myAnswer = ''
closest_to = someList[-1]
closest_diff = 0
for k in someDictionary:
    if someDictionary[k] in someList:
         myAnswer = k
         break; # stop the loop when exact match found
    diff = someDictionary[k] - closest_to
    if diff > 0 and diff < closest_diff:
         closest_diff = diff
         myAnswer = k # this would save key of larger but closest number to last in someList

首先使用列表理解收集所有值在 lst 中的键,如果没有匹配则过滤值大于 lst[-1] 的键。在根据键值与 lst 中最后一项的差异的 abs 值对它们进行排序后,取 0 索引,最接近的项目。

dct = {'1': 33, '2': 44, '3': 55, '4': 10, '5': 66, '6': 60}
lst = [51, 52, 53, 54, 55, 56]

my_answer = [int(i) for i in dct if dct[i] in lst]
if my_answer:
    print(*my_answer) # => 3
else:
    close = [i for i in dct if int(dct[i]) > max(lst)]
    closest = sorted(close, key=lambda x: abs(dct.get(x) - lst[-1]))[0]
    print(closest) # => 6

How can I find the key in someDictionary that matches an element in someList?

字典用于将键映射到值。在 O(1) 时间内不可能反向。但是您可以在 O(n) 时间内迭代,直到您可以将列表元素与字典值匹配。

您可以为此使用一个简单的 for 循环,迭代您的字典或列表。

d = {'1': 33, '2': 44, '3': 55, '4': 10, '5': 66, '6': 60}
L = [51, 52, 53, 54, 55, 56]

def find_key_dict(d, L):
    L_set = set(L)  # convert to set for O(1) lookup
    for k, v in d.items():
        if v in L_set:
            return k

def find_key_list(d, L):
    d_rev = {v: k for k, v in d.items()}  # reverse dict for value -> key map
    for i in L:
        if i in d_rev:
            return d_rev[i]

find_key_dict(d, L)  # '3'
find_key_list(d, L)  # '3'

也可以使用 next 将这些函数重写为 1 行生成器表达式,但这不一定更有效。

The second part I need to do is, if someList does not contain an element that is in someDictionary, find the value in someDictionary larger than (but closest to) the last element in someList

您可以使用 for... else... 构造和 min:

编写类似的函数
def find_key_dict(d, L):
    L_set = set(L)  # convert to set for O(1) lookup
    for k, v in d.items():
        if v in L_set:
            return k
    else:
        def min_func(x):
            diff = x[1] - L[-1]
            return diff <= 0, diff
        return min(d.items(), key=min_func)[0]

find_key_dict(d, L)  # '6'

对于第一个问题,您只是使用了错误的运算符来检查值是否在 someList

for k, v in someDictionary.items():
    if v in someList:
        myAnswer = k

关于第二个问题你可以这样扩展之前的代码

for k, v in someDictionary.items():
     if v in someList:
         myAnswer = k
         break
else:
     myAnswer = None
     for k, v in someDictionary.items():
         if v > someList[-1] and (myAnswer is None or v < someDictionary[myAnswer]):
             myAnswer = k

听起来你想要一个 bidict

>>> from bidict import bidict  # pip install bidict
>>> d = bidict({'1': 33, '2': 44, '3': 55, '4': 10, '5': 66, '6': 60})
>>> d['3'] 55
>>> d.inv[55] '3'

这允许在任一方向上进行 O(1) 次查找。现在,您可以遍历 someList 并有效地检查元素是否为 in d.inv

如果您的字典和列表很大,尤其是如果您有许多列表要针对同一个字典进行测试,则值得准备数据以便更快地执行。

__init__中最差的操作是排序,O(n*log(n))。它允许我们使用 bisect 在 O(log(n)) 的最后一个案例中找到最接近的值。

from bisect import bisect


class FindInDict:
    def __init__(self, someDictionary):
        self.dict_by_values = {val: key for key, val in someDictionary.items()}
        self.dict_values_set = set(sorted_values)
        self.sorted_values = sorted(someDictionary.values())

    def find(self, someList):
        common = set(someList).intersection(self.dict_values_set)
        if common:
            key = self.dict_by_values[common.pop()]
        else:
            closest_value = self.sorted_values[bisect(self.sorted_values, someList[-1])]
            key = self.dict_by_values[closest_value]
        return key



someDictionary = {'1': 33, '2': 44, '3': 55, '4': 10, '5': 66, '6': 60}    
finder = FindInDict(someDictionary)

finder.find([51, 52, 53, 54, 55, 56])
# 3

finder.find([51, 52, 53, 54, 56])  # no common value
# 6

这里有一些东西可以处理你的问题的两个部分,并且应该很容易修改以处理可能弹出的任何讨厌的 "edge-cases":

someDictionary = {'1': 33, '2': 44, '3': 55, '4': 10, '5': 66, '6': 60}
someList = [51, 52, 53, 54, 55, 56]

myAnswer = [key for key in someDictionary if someDictionary[key] in someList]
if not myAnswer:
    diffs = {dict_key: dict_value-someList[-1]
                for dict_key, dict_value in someDictionary.items()
                    if dict_value-someList[-1] > 0}
    myAnswer = [min(diffs, key=diffs.get)]  # Key of value with minimum
                                            # (positive) difference
print(myAnswer)