Python sözlük nesnesinden anahtar / değer çiftlerinin alt kümesi çıkarılsın mı?


313

Birkaç anahtar değer çifti (yaklaşık 16) olan büyük bir sözlük nesnesi var, ama sadece 3 tanesi ile ilgileniyorum. Bunu başarmanın en iyi yolu (en kısa / verimli / en zarif) nedir?

Bildiğim en iyi şey:

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

Eminim bundan daha zarif bir yol var. Fikirler?

Yanıtlar:


430

Deneyebilirsiniz:

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

... ya da içinde Python 3Python 2.7 veya sonraki sürümleri ( Fábio Diniz'e 2.7'de de çalıştığına işaret ettiği için teşekkürler ) :

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

Güncelleme: Håvard S'ın işaret ettiği gibi, anahtarların sözlükte olacağını bildiğinizi varsayıyorum - bu varsayımı yapamıyorsanız cevabına bakın . Alternatif olarak , yorumlarda timbo'nun işaret bigdictettiği gibi None, eşlemek için eksik olan bir anahtar istiyorsanız şunları yapabilirsiniz:

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

Python 3 kullanıyorsanız ve yalnızca orijinal sözlükte var olan yeni dikte anahtarları istiyorsanız, bazı set işlemlerini gerçekleştiren nesneleri görüntülemek için gerçeği kullanabilirsiniz:

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

5
Eğer başarısız olur bigdictiçermezk
Håvard Sı

7
Bunu aşağılamak biraz zor - bağlamdan bana bu tuşların sözlükte olduğu bilindiği oldukça açık görünüyordu ...
Mark Longair

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

9
@MarkLongair {big: k için bigdict [k] ('l', 'm', 'n') kullanım durumuna bağlı olarak, bigdict içindeki k} daha iyi olabilir, çünkü yalnızca gerçekte değerleri olan anahtarları saklar.
Briford Wylie

6
bigdict.keys() & {'l', 'm', 'n'} ==> bigdict.viewkeys() & {'l', 'm', 'n'} Python2.7
kxr

119

En azından biraz daha kısa:

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

8
Hiçbiri bigdict içinde değilse, Hiçbiri olarak ayarlamak yerine, bir anahtarı hariç tutmanın alternatif davranışı için +1.
DHJ

1
Alternatif olarak: dict((k,bigdict.get(k,defaultVal) for k in wanted_keys)tüm tuşlara sahip olmanız gerekir.
Thomas Andrews

2
Bu cevap bir "t" ile kaydedilir.
19:42, sakurashinken

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

16

Bahsedilen tüm yöntemler için biraz hız karşılaştırması:

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

Beklendiği gibi: sözlük anlama en iyi seçenektir.


İlk 3 işlem son ikisinden farklı bir şey yapıyor ve eğer keymevcut değilse hataya neden olacak bigdict.
naught101

12

Bu cevap, seçilen yanıta benzer bir sözlük kavrama kullanır, ancak eksik bir öğe hariç değildir.

python 2 sürümü:

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

python 3 sürümü:

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

2
... ama büyük dikse BÜYÜK ise, yine de tamamen tekrarlanacaktır (bu bir O (n) işlemi), tersi sadece 3 öğe (her biri bir O (1) işlemi) alacaktı.
wouter bolsterlee

1
Soru sadece 16 tuşun bir sözlüğü hakkında
Meow

6

Olabilir:

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

Python 3 aşağıdakileri bile destekler:

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

Sözlüğün varlığını aşağıdaki gibi kontrol edebileceğinizi unutmayın:

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

Resp. python 3 için

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

Eğer başarısız adeğilbigdict
Håvard S

3

Tamam, bu beni birkaç kez rahatsız eden bir şey, bu yüzden sorduğun için Jayesh'e teşekkür ederim.

Yukarıdaki cevaplar, herhangi bir kod gibi iyi bir çözüm gibi görünüyor, ancak bunu tüm kodunuzda kullanıyorsanız, IMHO işlevselliğini sarmak mantıklıdır. Ayrıca, burada iki olası kullanım durumu vardır: biri tüm anahtar kelimelerin orijinal sözlükte olup olmadığını önemsediğiniz. ve yapmadığınız bir yer. Her ikisine de eşit davranmak güzel olurdu.

Yani, iki penneth değere göre, bir sözlük alt sınıfı yazmanızı öneririm, ör.

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

Şimdi ile bir alt sözlüğü çıkarabilirsiniz

orig_dict.subdict(keywords)

Kullanım örnekleri:

#
## 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")

Yukarıdaki kodu çalıştırırsanız, aşağıdaki çıktıyı (biçimlendirme için üzgünüm) görmelisiniz (gibi bir şey):

Orijinal sözlük:
{'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}

Tek numaralı tuşlardan sözlük:
{'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 inşaatı başarısız:
orijinal sözlük bazı anahtarlar içermiyor

Bazı kötü anahtarlar kullanılarak oluşturulmuş sözlük:
{'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}


1
Alt sınıflandırma, varolan bir dikte nesnesinin alt sınıf türüne dönüştürülmesini gerektirir ve bu da pahalı olabilir. Neden sadece basit bir fonksiyon yazmıyorsunuz subdict(orig_dict, keys, …)?
musiphil

3

Ayrıca kullanabilirsiniz map( zaten tanımak için çok kullanışlı bir işlevdir):

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

Misal:

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))

Not: .get(key, None)Önceki cevaptan ödünç aldım :)


1

Yine bir tane daha (Mark Longair'in cevabını tercih ediyorum)

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])

onun için yavaş büyük dict en
KXR

0

çözüm

from operator import itemgetter
from typing import List, Dict, Union


def subdict(d: Union[Dict, List], columns: List[str]) -> Union[Dict, List[Dict]]:
    """Return a dict or list of dicts with subset of 
    columns from the d argument.
    """
    getter = itemgetter(*columns)

    if isinstance(d, list):
        result = []
        for subset in map(getter, d):
            record = dict(zip(columns, subset))
            result.append(record)
        return result
    elif isinstance(d, dict):
        return dict(zip(columns, getter(d)))

    raise ValueError('Unsupported type for `d`')

kullanım örnekleri

# pure dict

d = dict(a=1, b=2, c=3)
print(subdict(d, ['a', 'c']))

>>> In [5]: {'a': 1, 'c': 3}
# list of dicts

d = [
    dict(a=1, b=2, c=3),
    dict(a=2, b=4, c=6),
    dict(a=4, b=8, c=12),
]

print(subdict(d, ['a', 'c']))

>>> In [5]: [{'a': 1, 'c': 3}, {'a': 2, 'c': 6}, {'a': 4, 'c': 12}]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.