Python sözlüğü: Anahtar listesi için değer listesi alın


182

İlgili öğelerin bir listesini almak için sözlüğe ait anahtarların listesini kullanmanın yerleşik / hızlı bir yolu var mı?

Örneğin:

>>> mydict = {'one': 1, 'two': 2, 'three': 3}
>>> mykeys = ['three', 'one']

mykeysSözlükteki karşılık gelen değerleri bir liste olarak almak için nasıl kullanabilirim ?

>>> mydict.WHAT_GOES_HERE(mykeys)
[3, 1]

Yanıtlar:


206

Bir liste kavraması bunu yapmanın iyi bir yolu gibi görünmektedir:

>>> [mydict[x] for x in mykeys]
[3, 1]

1
Eğer mydictbir işlev çağrısı (döner dict olduğunu) daha sonra bu hak, işlev birden çok kez çağırır mı?
endolit

1
@endolith Evet olacak
Eric Romrell

108

List-comp'den başka birkaç yol:

  • Anahtar bulunamazsa liste oluşturun ve istisna atın: map(mydict.__getitem__, mykeys)
  • NoneAnahtar bulunamazsa liste oluşturun :map(mydict.get, mykeys)

Alternatif olarak, kullanmak operator.itemgetterbir tuple döndürebilir:

from operator import itemgetter
myvalues = itemgetter(*mykeys)(mydict)
# use `list(...)` if list is required

Not : Python3'te mapliste yerine yineleyici döndürür. list(map(...))Liste için kullanın .


54

Biraz hız karşılaştırması:

Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Dec  7 2015, 14:10:42) [MSC v.1500 64 bit (AMD64)] on win32
In[1]: l = [0,1,2,3,2,3,1,2,0]
In[2]: m = {0:10, 1:11, 2:12, 3:13}
In[3]: %timeit [m[_] for _ in l]  # list comprehension
1000000 loops, best of 3: 762 ns per loop
In[4]: %timeit map(lambda _: m[_], l)  # using 'map'
1000000 loops, best of 3: 1.66 µs per loop
In[5]: %timeit list(m[_] for _ in l)  # a generator expression passed to a list constructor.
1000000 loops, best of 3: 1.65 µs per loop
In[6]: %timeit map(m.__getitem__, l)
The slowest run took 4.01 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 853 ns per loop
In[7]: %timeit map(m.get, l)
1000000 loops, best of 3: 908 ns per loop
In[33]: from operator import itemgetter
In[34]: %timeit list(itemgetter(*l)(m))
The slowest run took 9.26 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 739 ns per loop

Bu yüzden liste anlama ve itemgetter bunu yapmanın en hızlı yoludur.

GÜNCELLEME: Büyük rastgele listeler ve haritalar için biraz farklı sonuçlar elde ettim:

Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Dec  7 2015, 14:10:42) [MSC v.1500 64 bit (AMD64)] on win32
In[2]: import numpy.random as nprnd
l = nprnd.randint(1000, size=10000)
m = dict([(_, nprnd.rand()) for _ in range(1000)])
from operator import itemgetter
import operator
f = operator.itemgetter(*l)
%timeit f(m)
%timeit list(itemgetter(*l)(m))
%timeit [m[_] for _ in l]  # list comprehension
%timeit map(m.__getitem__, l)
%timeit list(m[_] for _ in l)  # a generator expression passed to a list constructor.
%timeit map(m.get, l)
%timeit map(lambda _: m[_], l)
1000 loops, best of 3: 1.14 ms per loop
1000 loops, best of 3: 1.68 ms per loop
100 loops, best of 3: 2 ms per loop
100 loops, best of 3: 2.05 ms per loop
100 loops, best of 3: 2.19 ms per loop
100 loops, best of 3: 2.53 ms per loop
100 loops, best of 3: 2.9 ms per loop

Yani bu durumda net kazanır f = operator.itemgetter(*l); f(m)ve net yabancı: map(lambda _: m[_], l).

Python 3.6.4 için GÜNCELLEME:

import numpy.random as nprnd
l = nprnd.randint(1000, size=10000)
m = dict([(_, nprnd.rand()) for _ in range(1000)])
from operator import itemgetter
import operator
f = operator.itemgetter(*l)
%timeit f(m)
%timeit list(itemgetter(*l)(m))
%timeit [m[_] for _ in l]  # list comprehension
%timeit list(map(m.__getitem__, l))
%timeit list(m[_] for _ in l)  # a generator expression passed to a list constructor.
%timeit list(map(m.get, l))
%timeit list(map(lambda _: m[_], l)
1.66 ms ± 74.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
2.1 ms ± 93.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.58 ms ± 88.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.36 ms ± 60.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.98 ms ± 142 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.7 ms ± 284 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
3.14 ms ± 62.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Yani, Python 3.6.4 için sonuçlar neredeyse aynı.


15

İşte üç yol.

KeyErrorAnahtar bulunmadığında yükseltme :

result = [mapping[k] for k in iterable]

Eksik anahtarlar için varsayılan değerler.

result = [mapping.get(k, default_value) for k in iterable]

Eksik anahtarlar atlanıyor.

result = [mapping[k] for k in iterable if k in mapping]

found_keys = mapping.keys() & iterableTypeError: unsupported operand type(s) for &: 'list' and 'list'python 2.7'ye verir ; `found_keys = [anahtar yinelenebilirse mapping.keys () için anahtar] en iyi sonucu verir
NotGaeL

10

Bunu dene:

mydict = {'one': 1, 'two': 2, 'three': 3}
mykeys = ['three', 'one','ten']
newList=[mydict[k] for k in mykeys if k in mydict]
print newList
[3, 1]

7

Bunu dene:

mydict = {'one': 1, 'two': 2, 'three': 3}
mykeys = ['three', 'one'] # if there are many keys, use a set

[mydict[k] for k in mykeys]
=> [3, 1]

@PeterDeGlopper kafan karıştı. items()tercih edilir, ek bir arama yapmak zorunda değildir, burada herhangi bir len(mydict)*len(mykeys)işlem yoktur ! (bir set kullandığımı fark et)
Lópezscar López

@ ÓscarLópez Evet, sözlüğün her öğesini inceliyorsunuz. iteritems, ihtiyacınız olana kadar bunları vermez, bu nedenle bir ara liste oluşturmaktan kaçınır, ancak yine de, her bir kistteki her k için 'mykeys'de' k '(sipariş len (mykeys), çünkü bir liste) çalıştırırsınız. Tamamen gereksiz, sadece anahtarlarım üzerinde çalışan daha basit liste kavrama ile karşılaştırıldığında.
Peter DeGlopper

@ inspectorG4dget @PeterDeGlopper üyelik işlemi bitti mykeyssabit bir süre amortisman, bir liste değil, bir liste kullanıyorum
Óscar López

2
OP'nin listesini en azından bir kümeye dönüştürmek, onu lineer hale getirir, ancak yine de yanlış veri yapısında ve sipariş kaybında doğrusaldır. 10k sözlük ve mykeys'de 2 anahtar düşünün. Çözümünüz, basit liste kavraması için iki sözlük aramasına kıyasla 10k set üyelik testi yapar. Genel olarak, anahtar sayısının sözlük öğesi sayısından daha az olacağını varsaymak güvenlidir - değilse, yaklaşımınız tekrarlanan öğeleri atlayacaktır.
Peter DeGlopper


1

Pandas bunu çok zarif bir şekilde yapıyor, ancak ofc liste anlayışları her zaman teknik olarak Pythonic olacak. Şu anda bir hız karşılaştırması yapmak için zamanım yok (daha sonra tekrar gelip koyacağım):

import pandas as pd
mydict = {'one': 1, 'two': 2, 'three': 3}
mykeys = ['three', 'one']
temp_df = pd.DataFrame().append(mydict)
# You can export DataFrames to a number of formats, using a list here. 
temp_df[mykeys].values[0]
# Returns: array([ 3.,  1.])

# If you want a dict then use this instead:
# temp_df[mykeys].to_dict(orient='records')[0]
# Returns: {'one': 1.0, 'three': 3.0}

-1

Ya da sadece mydict.keys()sözlükler için yerleşik bir yöntem çağrısı. Ayrıca keşfedin mydict.values()ve mydict.items().

// Ah, OP yazısı beni şaşırttı.


5
Yerleşik yöntemler yararlıdır, ancak belirli bir anahtar listesinden karşılık gelen öğelerin bir listesini vermezler. Bu cevap, bu soruya doğru bir cevap değildir.
stenix

-1

Python'un kapanmasını takiben : belirli bir siparişle dikte değerlerinden bir liste oluşturmanın etkili yolu

Listeyi oluşturmadan anahtarları alma:

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import collections


class DictListProxy(collections.Sequence):
    def __init__(self, klist, kdict, *args, **kwargs):
        super(DictListProxy, self).__init__(*args, **kwargs)
        self.klist = klist
        self.kdict = kdict

    def __len__(self):
        return len(self.klist)

    def __getitem__(self, key):
        return self.kdict[self.klist[key]]


myDict = {'age': 'value1', 'size': 'value2', 'weigth': 'value3'}
order_list = ['age', 'weigth', 'size']

dlp = DictListProxy(order_list, myDict)

print(','.join(dlp))
print()
print(dlp[1])

Çıktı:

value1,value3,value2

value3

Listede verilen sıraya uyan


-2
reduce(lambda x,y: mydict.get(y) and x.append(mydict[y]) or x, mykeys,[])

eğer sözde olmayan anahtarlar varsa.

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.