Найдите элемент из списка в словаре и верните этот ключ

Если бы у меня был 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 someList[-1]

В этом случае myAnswer будет 6.

Немного запутался в вашем ответе 3. Вы вводили 55 или вы вводили someList? Вам нужен список ключей, которые соответствуют значениям в someList?

Stephen C 20.10.2018 16:16

@Stephen, извини, я ввожу someList; ищет любой элемент в someList, который соответствует значению в someDictionary. 55 в someList соответствует значению в someDictionary с ключом 3

yodish 20.10.2018 16:19

Вы имеете ввиду ключ '3'? 3 - это не ключ твоего дикта.

wim 20.10.2018 16:46

С учетом замечаний, мне нужно поработать над тем, чтобы лучше сформулировать свои вопросы, извините.

yodish 20.10.2018 16:51
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
4
157
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Первая часть, найдите список ключей, которые имеют словарное значение в списке.

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]

Благодарность; похоже, это возвращает список ['3']. Есть ли простой способ вернуть вместо этого int?

yodish 20.10.2018 16:25

если вы знаете, что все ключи имеют тип int, вы можете изменить [ключ для ключа ..] на [int (ключ) для ключа ...

Christian Sloper 20.10.2018 16:26

Это список, потому что он обрабатывает случай, когда есть более одного совпадения, если вам просто нужен первый элемент, вы можете перейти к res [0].

Christian Sloper 20.10.2018 16:28
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

Я ценю это!

yodish 20.10.2018 17:00

Сначала используйте понимание списка, чтобы собрать все ключи, значения которых находятся в lst, если нет совпадения, отфильтруйте ключи, значение которых больше, чем lst[-1]. После отсортируйте их по абсолютному значению разницы значений ключей и последнего элемента в lst и возьмите индекс 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 (п), пока не сможете сопоставить элемент списка со значением словаря.

Вы можете использовать для этого простой цикл 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, но это не обязательно будет более эффективным.

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'

Спасибо! Преобразование списка в набор пока работает хорошо. Я все еще ищу остальное ..

yodish 20.10.2018 16:37
Ответ принят как подходящий

Что касается первого вопроса, вы просто используете неправильный оператор, чтобы проверить, находится ли значение в 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

ну черт. Мне просто нужно было использовать in :) Спасибо!

yodish 20.10.2018 16:39

Я, вероятно, буду пересматривать этот пост много раз, когда начну писать код для крайних случаев; но это отвечает на мой вопрос. Спасибо!

yodish 20.10.2018 16:59

Похоже, вам нужен 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'

Это позволяет выполнять поиск О (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

Вот что-то, что обрабатывает обе части вашего вопроса и должно быть легко изменено для обработки любых надоедливых "крайних случаев", которые могут появиться:

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)

Другие вопросы по теме