Python - Trả về khóa N đầu tiên: các cặp giá trị từ dict


108

Hãy xem xét từ điển sau, d:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

Tôi muốn trả về cặp khóa N đầu tiên: giá trị từ d (N <= 4 trong trường hợp này). Phương pháp hiệu quả nhất để làm điều này là gì?


1
Thận trọng. Có vẻ như có nhiều thông tin sai lệch trong các câu trả lời. Các thử nghiệm của tôi cho thấy không có một giải pháp nào nhanh hơn list(d.items())[:4]. list () là cách triển khai cơ bản cho nhiều câu trả lời.
BSalita

Câu trả lời:


114

Không có điều gì như vậy một "n phím đầu tiên" bởi vì a dictkhông nhớ khóa nào đã được đưa vào đầu tiên.

Tuy nhiên, bạn có thể nhận được n cặp khóa-giá trị bất kỳ :

n_items = take(n, d.iteritems())

Điều này sử dụng việc triển khai taketừ các itertoolscông thức :

from itertools import islice

def take(n, iterable):
    "Return first n items of the iterable as a list"
    return list(islice(iterable, n))

Xem nó hoạt động trực tuyến: Ideone


Cập nhật cho Python 3.6

n_items = take(n, d.items())

42
Tôi tin rằng iteritemsnên được thay thế bằng itemscho folks trên Python 3
Monica Heddneck

1
@MonicaHeddneck, tuyệt vời, cảm ơn bạn đã thêm nhận xét này.
Karl Baker

12
Người mới bắt đầu ở đây - là take()một phần của cơ sở mã python ở đâu? Hoặc, nó hoàn toàn là chức năng bạn đã xác định trong câu trả lời của mình ở đây? Hỏi như thể đó là một phần của cơ sở mã, tôi không thể tìm / nhập nó. :)
Scott Borden

80

Một cách rất hiệu quả để truy xuất bất cứ thứ gì là kết hợp danh sách hoặc từ điển hiểu được với việc cắt. Nếu bạn không cần sắp xếp các mục (bạn chỉ muốn n cặp ngẫu nhiên), bạn có thể sử dụng cách hiểu từ điển như sau:

# Python 2
first2pairs = {k: mydict[k] for k in mydict.keys()[:2]}
# Python 3
first2pairs = {k: mydict[k] for k in list(mydict)[:2]}

Nói chung, một cách hiểu như thế này luôn chạy nhanh hơn vòng lặp "for x in y" tương đương. Ngoài ra, bằng cách sử dụng .keys () để tạo danh sách các khóa từ điển và cắt danh sách đó, bạn tránh 'chạm vào' bất kỳ khóa không cần thiết nào khi tạo từ điển mới.

Nếu bạn không cần khóa (chỉ các giá trị), bạn có thể sử dụng cách hiểu danh sách:

first2vals = [v for v in mydict.values()[:2]]

Nếu bạn cần các giá trị được sắp xếp dựa trên khóa của chúng, thì không có gì rắc rối hơn:

first2vals = [mydict[k] for k in sorted(mydict.keys())[:2]]

hoặc nếu bạn cũng cần chìa khóa:

first2pairs = {k: mydict[k] for k in sorted(mydict.keys())[:2]}

2
Điều này là một giải pháp tốt hơn nếu bạn muốn chọn N nhiều chính: cặp giá trị như một cuốn từ điển, không phải là một danh sách
fermat4214

1
@ fermat4214 Có phải là vấn đề không, nếu toàn bộ từ điển của tôi in ra khi tôi chạy bất kỳ lệnh nào trong số này?
Ted Taylor of Life

list (mydict) [: 2] thật lãng phí nếu bạn không cần sắp xếp từ điển mà chỉ cần 2 phần tử đầu tiên. Điều gì sẽ xảy ra nếu từ điển có 1 triệu cặp kv? Chuyển đổi toàn bộ thành một danh sách rất tốn kém. Giải pháp của Mark Byers tốt hơn nhiều.
JJ

Đây sẽ là giải pháp!
Guenter

14

Các Python dictkhông được sắp xếp theo thứ tự, vì vậy việc yêu cầu các phím "N đầu tiên" là vô nghĩa.

Các collections.OrderedDictlớp hiện có sẵn nếu đó là những gì bạn cần. Bạn có thể có được bốn yếu tố đầu tiên một cách hiệu quả là

import itertools
import collections

d = collections.OrderedDict((('foo', 'bar'), (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')))
x = itertools.islice(d.items(), 0, 4)

for key, value in x:
    print key, value

itertools.islicecho phép bạn lấy một phần tử từ bất kỳ trình vòng lặp nào một cách lười biếng. Nếu bạn muốn kết quả có thể sử dụng lại được, bạn cần chuyển đổi nó thành một danh sách hoặc một cái gì đó, như sau:

x = list(itertools.islice(d.items(), 0, 4))

Không có vẻ lười biếng. Dài gấp đôi so với `list (d.items ()) [: 4]
BSalita

12
foo = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5, 'f':6}
iterator = iter(foo.items())
for i in range(3):
    print(next(iterator))

Về cơ bản, biến chế độ xem (dict_items) thành một trình lặp, rồi lặp lại nó với next ().


2
Câu trả lời tuyệt vời, đây là câu trả lời duy nhất trên trang này phù hợp với tôi và cũng có thể đọc được. Ngoài ra, tôi có thể xác minh điều này hoạt động với Python 3, điều mà một số câu trả lời cũ hơn dường như không.
cdahms

7

Không thấy nó trên đây. Sẽ không được sắp xếp theo thứ tự nhưng là cú pháp đơn giản nhất nếu bạn chỉ cần lấy một số phần tử từ từ điển.

n = 2
{key:value for key,value in d.items()[0:n]}

7
Tôi cố gắng bạn mã nhưng tôi nhận được lỗi này: TypeError: 'dict_items' object is not subscriptable {key:value for key,value in stocks.items()[0:n]} (cổ phiếu là tên của từ điển của tôi)
Moondra

2
@Moondra - Phải chuyển đổi vào danh sách trước khi chạy qua các mục từ điển. Đoạn mã trên, dòng hoạt động nếu {key: value for key, value in list (d.items ()) [0: n]}
Rajesh Mappu 14/08/18

{A: N for (A, N) in [x for x in d.items ()] [: 4]}
farid khafizov

6

Để lấy N phần tử hàng đầu từ từ điển python của bạn, người ta có thể sử dụng dòng mã sau:

list(dictionaryName.items())[:N]

Trong trường hợp của bạn, bạn có thể thay đổi nó thành:

list(d.items())[:4]

3

Xem PEP 0265 về phân loại từ điển. Sau đó, sử dụng mã có thể lặp lại nói trên.

Nếu bạn cần hiệu quả hơn trong các cặp khóa-giá trị đã được sắp xếp. Sử dụng một cấu trúc dữ liệu khác. Đó là, một thứ duy trì thứ tự được sắp xếp và các liên kết khóa-giá trị.

Ví dụ

import bisect

kvlist = [('a', 1), ('b', 2), ('c', 3), ('e', 5)]
bisect.insort_left(kvlist, ('d', 4))

print kvlist # [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]

3

trong py3, điều này sẽ thực hiện thủ thuật

{A:N for (A,N) in [x for x in d.items()][:4]}

{'a': 3, 'b': 2, 'c': 3, 'd': 4}


2

chỉ cần thêm câu trả lời bằng zip,

{k: d[k] for k, _ in zip(d, range(n))}

1

Điều này phụ thuộc vào điều gì là 'hiệu quả nhất' trong trường hợp của bạn.

Nếu bạn chỉ muốn một mẫu bán ngẫu nhiên của một từ điển khổng lồ foo, hãy sử dụng foo.iteritems()và lấy nhiều giá trị từ nó khi bạn cần, đó là một thao tác lười biếng nhằm tránh tạo danh sách khóa hoặc mục rõ ràng.

Nếu bạn cần sắp xếp các khóa trước tiên, không có cách nào khác là sử dụng một cái gì đó như keys = foo.keys(); keys.sort()hoặc sorted(foo.iterkeys()), bạn sẽ phải xây dựng một danh sách các khóa rõ ràng. Sau đó cắt hoặc lặp qua N đầu tiên keys.

BTW tại sao bạn quan tâm đến cách 'hiệu quả'? Bạn đã lập hồ sơ cho chương trình của mình? Nếu không, hãy sử dụng cách rõ ràngdễ hiểu trước. Rất có thể nó sẽ hoạt động khá tốt mà không trở thành điểm nghẽn.


Đây là một ứng dụng cho một chương trình tài chính và tôi cố gắng xây dựng mọi dòng mã hiệu quả nhất có thể. Tôi đã không lập hồ sơ chương trình và đồng ý rằng điều này có thể sẽ không phải là một cổ chai nhưng tôi thích yêu cầu các giải pháp hiệu quả theo mặc định. Cảm ơn vi đa trả lơi.
Jason Strimpel

0

Bạn có thể tiếp cận điều này theo một số cách. Nếu thứ tự quan trọng, bạn có thể làm điều này:

for key in sorted(d.keys()):
  item = d.pop(key)

Nếu đơn đặt hàng không phải là mối quan tâm, bạn có thể làm điều này:

for i in range(4):
  item = d.popitem()

Trong đoạn mã đầu tiên, bạn có thể nên gọi nó valuehơn là itemcho rõ ràng.
agf

0

Từ điển không có thứ tự, vì vậy trước khi chọn N cặp giá trị khóa hàng đầu, hãy sắp xếp nó.

import operator
d = {'a': 3, 'b': 2, 'c': 3, 'd': 4}
d=dict(sorted(d.items(),key=operator.itemgetter(1),reverse=True))
#itemgetter(0)=sort by keys, itemgetter(1)=sort by values

Bây giờ chúng ta có thể thực hiện việc truy xuất các phần tử 'N' hàng đầu :, bằng cách sử dụng cấu trúc phương thức như sau:

def return_top(elements,dictionary_element):
    '''Takes the dictionary and the 'N' elements needed in return
    '''
    topers={}
    for h,i in enumerate(dictionary_element):
        if h<elements:
            topers.update({i:dictionary_element[i]})
    return topers

để lấy 2 phần tử hàng đầu thì chỉ cần sử dụng cấu trúc này:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4}
d=dict(sorted(d.items(),key=operator.itemgetter(1),reverse=True))
d=return_top(2,d)
print(d)

0

Đối với Python 3 trở lên, để chọn n cặp đầu tiên

n=4
firstNpairs = {k: Diction[k] for k in list(Diction.keys())[:n]}

0

coi một mệnh lệnh

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

from itertools import islice
n = 3
list(islice(d.items(),n))

islice sẽ thực hiện thủ thuật :) hy vọng nó sẽ giúp!


0

Điều này có thể không được thanh lịch cho lắm, nhưng phù hợp với tôi:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

x= 0
for key, val in d.items():
    if x == 2:
        break
    else:
        x += 1
        # Do something with the first two key-value pairs

0

Tôi đã thử một số câu trả lời ở trên và lưu ý rằng một số câu trả lời phụ thuộc vào phiên bản và không hoạt động trong phiên bản 3.7.

Tôi cũng lưu ý rằng kể từ 3.6, tất cả các từ điển đều được sắp xếp theo trình tự mà các mục được chèn vào.

Mặc dù các từ điển đã được sắp xếp thứ tự kể từ ngày 3.6, một số câu lệnh mà bạn mong đợi làm việc với các cấu trúc có thứ tự dường như không hoạt động.

Câu trả lời cho câu hỏi OP phù hợp nhất với tôi.

itr = iter(dic.items())
lst = [next(itr) for i in range(3)]

FYI, chậm hơn 5 lần so vớilst = list(d.items())[:N]
BSalita
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.