Извлечь подмножество пар ключ-значение из объекта словаря Python?

У меня есть большой словарь, у которого есть несколько ключевых пар значений (около 16), но меня интересуют только 3 из них. Каков наилучший способ (кратчайший/эффективный/самый элегантный) для достижения этого?

Самое лучшее, что я знаю:

bigdict = {'a':1,'b':2,....,'z':26} 
subdict = {'l':bigdict['l'], 'm':bigdict['m'], 'n':bigdict['n']}

Я уверен, что есть более элегантный способ, чем это. Идеи?

Ответ 1

Вы можете попробовать:

dict((k, bigdict[k]) for k in ('l', 'm', 'n'))

... или в Python 3 Версии Python 2.7 или более поздние (спасибо Фабио Динизу за то, что он указал, что он работает и в 2.7):

{k: bigdict[k] for k in ('l', 'm', 'n')}

Обновление: Как указывает Håvard S, я предполагаю, что вы знаете, что ключи будут в словаре - посмотрите его ответ, если вы не можете сделать такое предположение. В качестве альтернативы, как указывает Тимбо в комментариях, если вы хотите, чтобы ключ, отсутствующий в bigdict отображался на None, вы можете сделать:

{k: bigdict.get(k, None) for k in ('l', 'm', 'n')}

Если вы используете Python 3 и вам нужны только ключи в новом dict, которые фактически существуют в исходном, вы можете использовать этот факт для просмотра объектов, реализующих некоторые операции над множествами:

{k: bigdict[k] for k in bigdict.keys() & {'l', 'm', 'n'}}

Ответ 2

Немного короче, по крайней мере:

wanted_keys = ['l', 'm', 'n'] # The keys you want
dict((k, bigdict[k]) for k in wanted_keys if k in bigdict)

Ответ 3

interesting_keys = ('l', 'm', 'n')
subdict = {x: bigdict[x] for x in interesting_keys if x in bigdict}

Ответ 4

Небольшое сравнение скорости для всех упомянутых методов:

Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Jan 29 2016, 14:26:21) [MSC v.1500 64 bit (AMD64)] on win32
In[2]: import numpy.random as nprnd
keys = nprnd.randint(1000, size=10000)
bigdict = dict([(_, nprnd.rand()) for _ in range(1000)])

%timeit {key:bigdict[key] for key in keys}
%timeit dict((key, bigdict[key]) for key in keys)
%timeit dict(map(lambda k: (k, bigdict[k]), keys))
%timeit dict(filter(lambda i:i[0] in keys, bigdict.items()))
%timeit {key:value for key, value in bigdict.items() if key in keys}
100 loops, best of 3: 3.09 ms per loop
100 loops, best of 3: 3.72 ms per loop
100 loops, best of 3: 6.63 ms per loop
10 loops, best of 3: 20.3 ms per loop
100 loops, best of 3: 20.6 ms per loop

Как и ожидалось: наилучшим вариантом является понимание словаря.

Ответ 5

В этом ответе используется понимание словаря, похожее на выбранный ответ, но не за исключением отсутствующего элемента.

версия python 2:

{k:v for k, v in bigDict.iteritems() if k in ('l', 'm', 'n')}

версия python 3:

{k:v for k, v in bigDict.items() if k in ('l', 'm', 'n')}

Ответ 6

Может быть:

subdict=dict([(x,bigdict[x]) for x in ['l', 'm', 'n']])

Python 3 поддерживает даже следующее:

subdict={a:bigdict[a] for a in ['l','m','n']}

Обратите внимание, что вы можете проверить наличие в словаре следующим образом:

subdict=dict([(x,bigdict[x]) for x in ['l', 'm', 'n'] if x in bigdict])

соотв. для python 3

subdict={a:bigdict[a] for a in ['l','m','n'] if a in bigdict}

Ответ 7

Вы также можете использовать карту (которая очень полезная функция, чтобы узнать в любом случае):

sd = dict(map(lambda k: (k, l.get(k, None)), l))

Пример:

large_dictionary = {'a1':123, 'a2':45, 'a3':344} list_of_keys = ['a1', 'a3'] small_dictionary = dict(map(lambda key: (key, large_dictionary.get(key, None)), list_of_keys))

PS. Я заимствовал ключ .get(key, None) из предыдущего ответа:)

Ответ 8

Хорошо, это то, что беспокоило меня несколько раз, поэтому спасибо Джайешу за то, что он спросил.

Ответы выше выглядят как хорошее решение, как любое, но если вы используете это по всему вашему коду, имеет смысл обернуть функциональность IMHO. Кроме того, здесь есть два возможных варианта использования: один, где вас беспокоит, находятся ли все ключевые слова в оригинальном словаре. и тот, где вы этого не делаете. Было бы неплохо относиться ко всем одинаково.

Итак, для моего двухзначного значения я предлагаю написать подкласс класса, например.

class my_dict(dict):
    def subdict(self, keywords, fragile=False):
        d = {}
        for k in keywords:
            try:
                d[k] = self[k]
            except KeyError:
                if fragile:
                    raise
        return d

Теперь вы можете вытащить суб-словарь с помощью

orig_dict.subdict(keywords)

Примеры использования:

#
## our keywords are letters of the alphabet
keywords = 'abcdefghijklmnopqrstuvwxyz'
#
## our dictionary maps letters to their index
d = my_dict([(k,i) for i,k in enumerate(keywords)])
print('Original dictionary:\n%r\n\n' % (d,))
#
## constructing a sub-dictionary with good keywords
oddkeywords = keywords[::2]
subd = d.subdict(oddkeywords)
print('Dictionary from odd numbered keys:\n%r\n\n' % (subd,))
#
## constructing a sub-dictionary with mixture of good and bad keywords
somebadkeywords = keywords[1::2] + 'A'
try:
    subd2 = d.subdict(somebadkeywords)
    print("We shouldn't see this message")
except KeyError:
    print("subd2 construction fails:")
    print("\toriginal dictionary doesn't contain some keys\n\n")
#
## Trying again with fragile set to false
try:
    subd3 = d.subdict(somebadkeywords, fragile=False)
    print('Dictionary constructed using some bad keys:\n%r\n\n' % (subd3,))
except KeyError:
    print("We shouldn't see this message")

Если вы запустите весь вышеуказанный код, вы увидите (что-то вроде) следующий результат (извините за форматирование):

Оригинальный словарь:
       {'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3, 'g': 6, 'f': 5,         'i': 8, 'h': 7, 'k': 10, 'j': 9, 'm': 12, 'l': 11, 'o': 14,         'n': 13, 'q': 16, 'p': 15, 's': 18, 'r': 17, 'u': 20,         't': 19, 'w': 22, 'v': 21, 'y': 24, 'x': 23, 'z': 25}

Словарь с нечетными номерами:
       {'a': 0, 'c': 2, 'e': 4, 'g': 6, 'i': 8, 'k': 10, 'm': 12, 'o': 14, ' q ': 16,' s ': 18,' u ': 20,' w ': 22,' y ': 24}

Неполадка строительства subd2:
       оригинальный словарь не содержит некоторых клавиш

Словарь, построенный с использованием некорректных ключей:
       {'b': 1, 'd': 3, 'f': 5, 'h': 7, 'j': 9, 'l': 11, 'n': 13, 'p': 15, ' r ': 17,' t ': 19,' v ': 21,' x ': 23,' z ': 25}

Ответ 9

Еще один (я предпочитаю ответ Марк Лонгэй)

di = {'a':1,'b':2,'c':3}
req = ['a','c','w']
dict([i for i in di.iteritems() if i[0] in di and i[0] in req])

Ответ 10

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

>>> base = dict( a=1, b=2, c=3, d=4, e=5, f=6, g=7 )
>>> required = { 'a', 'c', 'g' } # or anything containing the required keys
>>> subdict = base.fromkeys( required )
>>> subdict
{'g': 7, 'a': 1, 'c': 3}

Должно быть быстрее, чем что-либо выше. ;)