Kamus Python: Dapatkan daftar nilai untuk daftar kunci

182

Apakah ada cara bawaan / cepat untuk menggunakan daftar kunci ke kamus untuk mendapatkan daftar item yang sesuai?

Misalnya saya punya:

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

Bagaimana saya bisa menggunakan mykeysuntuk mendapatkan nilai yang sesuai di kamus sebagai daftar?

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

Jawaban:

206

Pemahaman daftar tampaknya menjadi cara yang baik untuk melakukan ini:

>>> [mydict[x] for x in mykeys]
[3, 1]
FazJaxton
sumber
1
Jika mydictpanggilan fungsi (yang mengembalikan dict) maka ini memanggil fungsi beberapa kali, kan?
endolith
1
@endolith Ya itu akan
Eric Romrell
108

Beberapa cara lain selain daftar-comp:

  • Buat daftar dan buang pengecualian jika kunci tidak ditemukan: map(mydict.__getitem__, mykeys)
  • Buat daftar dengan Nonejika kunci tidak ditemukan:map(mydict.get, mykeys)

Atau, menggunakan operator.itemgetterdapat mengembalikan tuple:

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

Catatan : di Python3, mapmengembalikan iterator daripada daftar. Gunakan list(map(...))untuk daftar.

Jon Clements
sumber
54

Perbandingan kecepatan kecil:

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

Jadi pemahaman daftar dan itemgetter adalah cara tercepat untuk melakukan ini.

PEMBARUAN: Untuk daftar dan peta acak besar, saya mendapat hasil yang sedikit berbeda:

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

Jadi dalam hal ini pemenang adalah f = operator.itemgetter(*l); f(m), dan luar jelas: map(lambda _: m[_], l).

UPDATE untuk Python 3.6.4:

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)

Jadi, hasil untuk Python 3.6.4 hampir sama.

Sklavit
sumber
15

Berikut ini tiga cara.

Meningkatkan KeyErrorketika kunci tidak ditemukan:

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

Nilai default untuk kunci yang hilang.

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

Melewati kunci yang hilang.

result = [mapping[k] for k in iterable if k in mapping]
Tidak Terdaftar
sumber
found_keys = mapping.keys() & iterableberikan TypeError: unsupported operand type(s) for &: 'list' and 'list'pada python 2.7; `found_keys = [kunci untuk kunci di mapping.keys () jika kunci dalam iterable] berfungsi paling baik
NotGaeL
10

Coba ini:

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]
Vikram Singh Chandel
sumber
7

Coba ini:

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]
Óscar López
sumber
@PeterDeGlopper Anda bingung. items()lebih disukai, tidak harus melakukan pencarian tambahan, tidak ada len(mydict)*len(mykeys)operasi di sini! (perhatikan bahwa saya menggunakan set)
Óscar López
@ ÓscarLópez Ya, Anda memeriksa setiap elemen kamus. iteritem tidak menghasilkannya sampai Anda membutuhkannya, jadi ia menghindari pembuatan daftar perantara, tetapi Anda masih menjalankan 'k in mykeys' (order len (mykeys), karena itu adalah daftar) untuk setiap k dalam mydict. Benar-benar tidak perlu, dibandingkan dengan pemahaman daftar sederhana yang hanya berjalan di atas mykey.
Peter DeGlopper
@ inspectorG4dget @PeterDeGlopper operasi keanggotaan selesai mykeysdiamortisasi waktu konstan, saya menggunakan satu set, bukan daftar
Óscar López
2
Mengubah daftar OP ke set setidaknya membuatnya linear, tetapi masih linear pada struktur data yang salah serta kehilangan pesanan. Pertimbangkan kasus kamus 10k dan 2 kunci di mykeys. Solusi Anda membuat tes keanggotaan set 10k, dibandingkan dengan dua pencarian kamus untuk pemahaman daftar sederhana. Secara umum tampaknya aman untuk mengasumsikan bahwa jumlah kunci akan lebih kecil dari jumlah elemen kamus - dan jika tidak, pendekatan Anda akan menghilangkan elemen berulang.
Peter DeGlopper
4
new_dict = {x: v for x, v in mydict.items() if x in mykeys}
Pavel Minenkov
sumber
1

Panda melakukan ini dengan sangat elegan, meskipun pemahaman daftar ofc akan selalu lebih Pythonic secara teknis. Saya tidak punya waktu untuk membandingkan kecepatan sekarang (saya akan kembali lagi nanti):

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}
abby sobh
sumber
-1

Atau hanya mydict.keys()itu panggilan metode builtin untuk kamus. Juga jelajahi mydict.values()danmydict.items() .

// Ah, pos OP membuatku bingung.

Edgar Aroutiounian
sumber
5
Metode bawaan berguna tetapi tidak memberikan daftar item yang sesuai dari daftar kunci yang diberikan. Jawaban ini bukan jawaban yang benar untuk pertanyaan khusus ini.
stenix
-1

Berikut penutupan Python: cara efisien untuk membuat daftar dari nilai dict dengan urutan yang diberikan

Mengambil kunci tanpa membuat daftar:

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

Hasil:

value1,value3,value2

value3

Yang cocok dengan urutan yang diberikan oleh daftar

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

memetikan ada kunci tidak dalam dikt.

yupbank
sumber