简体   繁体   中英

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

If I had someDictionary defined as

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

and someList defined as

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

how can I find the key in someDictionary that matches an element in someList ? For now, I'm assuming there won't be more than one match.

I would think it would be something like this:

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

Given the code above, myAnswer would be 3

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 someList[-1]

In that case, myAnswer would be 6

It sounds like you want a 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'

This allows O(1) lookups in either direction. Now, you can loop over someList and check if an element is in d.inv efficiently.

First part, Find the list of keys that have a dictionary value in list.

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]

second part, if no result from first part, find the key with the closest larger value (continuing):

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

First use list comprehension to gather all keys whose values are in lst , if there is no match then filter for keys whose value is larger than lst[-1] . After sort them based on the abs value of the difference of the keys values and the last item in lst and take the 0 index, closest item.

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 ?

A dictionary is used map keys to values. The reverse isn't possible in O(1) time. But you can iterate in O( n ) time until you can match a list element with a dictionary value.

You can use a simple for loop for this, either iterating your dictionary or list.

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'

It's also possible to rewrite these functions as 1-line generator expressions with next , but this won't necessarily be more efficient.

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

You can write a similar function utilising a for... else... construct with 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'

For the first question, you are just using the wrong operator to check if the value is in someList

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

About the second question you can extend the previous code in this way

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

If your dictionary and list are large, and especially if you have many lists to test against the same dictionary, it can be worth preparing your data in order to have a faster execution.

The worst operation in __init__ is sorting, which is O(n*log(n)). It allows us to use bisect to find the closest value in your last case in 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

Here's something that handles both parts of your question and should be easy to modify to handle any pesky "edge-cases" that might pop up:

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM