Từ điển Python: Nhận danh sách các giá trị cho danh sách các khóa


182

Có cách nào tích hợp / nhanh chóng để sử dụng danh sách các khóa vào từ điển để lấy danh sách các mục tương ứng không?

Chẳng hạn tôi có:

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

Làm cách nào tôi có thể sử dụng mykeysđể lấy các giá trị tương ứng trong từ điển dưới dạng danh sách?

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

Câu trả lời:


206

Một sự hiểu biết danh sách dường như là một cách tốt để làm điều này:

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

1
Nếu mydictlà một lời gọi hàm (trả về một dict) thì điều này gọi hàm nhiều lần, phải không?
endolith

1
@endolith Có, nó sẽ
Eric Romrell

108

Một vài cách khác ngoài list-comp:

  • Xây dựng danh sách và ném ngoại lệ nếu không tìm thấy khóa: map(mydict.__getitem__, mykeys)
  • Xây dựng danh sách với Nonenếu không tìm thấy khóa:map(mydict.get, mykeys)

Ngoài ra, sử dụng operator.itemgettercó thể trả về một tuple:

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

Lưu ý : trong Python3, maptrả về một iterator chứ không phải là một danh sách. Sử dụng list(map(...))cho một danh sách.


54

Một chút so sánh tốc độ:

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

Vì vậy, hiểu danh sách và itemgetter là cách nhanh nhất để làm điều này.

CẬP NHẬT: Đối với các danh sách và bản đồ ngẫu nhiên lớn, tôi có một số kết quả khác nhau:

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

Vì vậy, trong trường hợp này, người chiến thắng rõ ràng là f = operator.itemgetter(*l); f(m), và người ngoài cuộc rõ ràng : map(lambda _: m[_], l).

CẬP NHẬT cho 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)

Vì vậy, kết quả cho Python 3.6.4 gần như giống nhau.


15

Đây là ba cách.

Tăng KeyErrorkhi không tìm thấy khóa:

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

Giá trị mặc định cho các khóa bị thiếu.

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

Bỏ qua các phím bị thiếu.

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

found_keys = mapping.keys() & iterablecho TypeError: unsupported operand type(s) for &: 'list' and 'list'trăn 2.7; `Found_keys = [khóa cho khóa trong maps.keys () nếu khóa trong iterable] hoạt động tốt nhất
NotGaeL

10

Thử cái này:

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

Thử cái này:

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 bạn đang bối rối. items()được ưa thích, nó không phải thực hiện tra cứu bổ sung, không có len(mydict)*len(mykeys)hoạt động nào ở đây! (lưu ý rằng tôi đang sử dụng một bộ)
Óscar López

@ ÓscarLópez Có, bạn đang kiểm tra mọi yếu tố của từ điển. iteritems không mang lại chúng cho đến khi bạn cần chúng, vì vậy nó tránh xây dựng một danh sách trung gian, nhưng bạn vẫn chạy 'k in mykeys' (order len (mykey), vì đó là danh sách) cho mọi k trong mydict. Hoàn toàn không cần thiết, so với việc hiểu danh sách đơn giản hơn chỉ chạy trên mykey.
Peter DeGlopper

@ InspectorG4dget @PeterDeGlopper, hoạt động thành viên mykeysđược khấu hao theo thời gian không đổi, tôi đang sử dụng một bộ chứ không phải danh sách
Óscar López

2
Chuyển đổi danh sách của OP thành một tập hợp ít nhất làm cho nó thành tuyến tính, nhưng nó vẫn tuyến tính trên cấu trúc dữ liệu sai cũng như mất trật tự. Hãy xem xét trường hợp của một từ điển 10k và 2 khóa trong mykey. Giải pháp của bạn khiến 10k thiết lập các bài kiểm tra thành viên, so với hai lần tra cứu từ điển để hiểu danh sách đơn giản. Nhìn chung, có vẻ an toàn khi giả định rằng số lượng khóa sẽ nhỏ hơn số lượng phần tử từ điển - và nếu không, cách tiếp cận của bạn sẽ bỏ qua các phần tử lặp lại.
Peter DeGlopper


1

Pandas thực hiện điều này rất thanh lịch, mặc dù việc hiểu danh sách sẽ luôn mang tính kỹ thuật hơn Pythonic. Tôi không có thời gian để đưa ra một so sánh tốc độ ngay bây giờ (tôi sẽ quay lại sau và đưa nó vào):

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

Hoặc chỉ mydict.keys()Đó là một phương thức dựng sẵn gọi cho từ điển. Cũng khám phá mydict.values()mydict.items().

// À, bài OP làm tôi bối rối.


5
Các phương thức tích hợp rất hữu ích nhưng chúng không đưa ra danh sách các mục tương ứng từ một danh sách các khóa đã cho. Câu trả lời này không phải là một câu trả lời đúng cho câu hỏi cụ thể này.
stenix

-1

Sau khi đóng cửa Python: cách hiệu quả để tạo danh sách từ các giá trị dict với một thứ tự nhất định

Lấy các khóa mà không xây dựng danh sách:

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

Đầu ra:

value1,value3,value2

value3

Khớp với thứ tự được đưa ra bởi danh sách


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

Trong đó có các phím không trong dict.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.