Znajdź element z listy w słowniku i powrót tego klucza

głosy
1

Gdybym someDictionaryzdefiniowany jako

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

i someListokreśla się jako

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

Jak mogę znaleźć klucz w someDictionarypasujący element w someList? Na razie jestem przy założeniu, że nie będzie więcej niż jeden mecz.

Myślę, że byłoby mniej więcej tak:

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

Biorąc pod uwagę powyższy kod, myAnswerbyłaby3

Druga część muszę zrobić to, jeśli jakaśLista nie zawiera element, który jest w someDictionary, znaleźć wartość w someDictionarywiększy niż (ale najbliżej) ostatni element jakiejśListysomeList[-1]

W tym przypadku byłoby myAnswer 6

Utwórz 20/10/2018 o 14:12
źródło użytkownik
W innych językach...                            


8 odpowiedzi

głosy
2

Pierwsza część, znaleźć listę kluczy, które mają wartość słownika w liście.

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]

Druga część, jeśli nie wynikają z pierwszej części, znaleźć klucz z najbliższej większej wartości (ciągły):

if not res:
    res = min ([(value, key) for key, value in someDictionary.items() if value > max(someList) ])[1]
Odpowiedział 20/10/2018 o 14:20
źródło użytkownik

głosy
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
Odpowiedział 20/10/2018 o 14:24
źródło użytkownik

głosy
1

Pierwsza lista korzystanie ze zrozumieniem, aby zebrać wszystkie klucze, których wartości są lst, jeśli nie ma odpowiednika następnie filtrować na klucze, których wartość jest większa niż lst[-1]. Po sortować je na podstawie wartości abs różnicy wartości kluczy i ostatniego elementu lsti podjąć 0indeks, najbliższy element.

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
Odpowiedział 20/10/2018 o 14:25
źródło użytkownik

głosy
1

Jak mogę znaleźć klucz w someDictionarypasujący element w someList?

Słownik służy klucze map do wartości. Odwrotna nie jest możliwe w O (1) czas. Ale można iteracyjne w O ( n ) czasu, aż można dopasować element listy o wartości słownika.

Można użyć prostego forpętlę na to, czy iteracja słownika lub 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'

Możliwe jest również, aby przepisać te funkcje jako 1-LINE z generatora wyrażeń next, ale to nie musi być bardziej efektywne.

Druga część muszę zrobić to, jeśli someListnie zawierają element, który jest w someDictionary, znaleźć wartość w someDictionary większy niż (ale najbliżej) ostatni elementsomeList

Można pisać podobną funkcję wykorzystujący for... else...konstrukcję z 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'
Odpowiedział 20/10/2018 o 14:27
źródło użytkownik

głosy
1

Na pierwsze pytanie, to są tylko przy użyciu niewłaściwego operatora, aby sprawdzić, czy wartość jest w someList

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

O drugie pytanie można przedłużyć poprzedni kod w ten sposób

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
Odpowiedział 20/10/2018 o 14:33
źródło użytkownik

głosy
3

Brzmi to jak chcesz 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'

Pozwala to O (1) wyszukiwań w obu kierunkach. Teraz możesz pętli nad someListi sprawdzić, czy element jest in d.invsprawnie.

Odpowiedział 20/10/2018 o 14:38
źródło użytkownik

głosy
1

Jeśli słownik i liście są duże, a zwłaszcza jeśli masz wiele list do testowania przeciwko tym samym słowniku, to może być warte przygotowanie danych w celu uzyskania szybszej realizacji.

Najgorsze operacja __init__jest sortowania, co O (N * log (n)). To pozwala nam wykorzystać bisect, aby znaleźć najbliższą wartość w swoim ostatnim przypadku w czasie 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
Odpowiedział 20/10/2018 o 15:08
źródło użytkownik

głosy
1

Oto coś, co obsługuje obie części Twojego pytania i powinny być łatwe do modyfikacji, aby obsłużyć wszystkie brzydkie „edge-przypadki”, które mogłyby pojawiają się:

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)
Odpowiedział 20/10/2018 o 16:00
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more