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]

Jawaban:


206

Pemahaman daftar tampaknya menjadi cara yang baik untuk melakukan ini:

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

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.


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.


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]

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]

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]

@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


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}

-1

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

// Ah, pos OP membuatku bingung.


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


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

memetikan ada kunci tidak dalam dikt.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.