Lấy khóa tương ứng với giá trị tối thiểu trong từ điển


305

Nếu tôi có một từ điển Python, làm thế nào để tôi lấy khóa cho mục nhập chứa giá trị tối thiểu?

Tôi đã suy nghĩ về một cái gì đó để làm với min()chức năng ...

Đưa ra đầu vào:

{320:1, 321:0, 322:3}

Nó sẽ trở lại 321.


Typo trong lợi nhuận đã nêu của bạn? Nếu không, tại sao lại là 321? Không phải là 320 sao?
GreenMatt

3
@myself: Được rồi, bây giờ tôi hiểu - điều muốn là chìa khóa cho mục nhập trong đó giá trị của mục nhập là tối thiểu. Xin vui lòng từ ngữ tốt hơn cho câu hỏi, như những người khác rõ ràng nghĩ giống như tôi đã làm.
GreenMatt

2
Ngày nhận thức về cấu trúc dữ liệu: nếu bạn chỉ truy vấn (hoặc xóa) phần tử tối thiểu, hãy xem xét sử dụng hàng đợi ưu tiên hoặc heap.
Đại tá Panic

Câu trả lời:


597

Tốt nhất: min(d, key=d.get)- không có lý do gì để can thiệp vào một lambdalớp không xác định vô dụng hoặc trích xuất các mục hoặc khóa!


5
@ KarelBílek có nghĩa là bạn đã chuyển vào dưới dạng "d" một danh sách [11, 22, 33], ví dụ , thay vì từ điển, vd {1: 11, 2:22, 3:33}. 'D.get' là hợp lệ cho một từ điển, nhưng không phải cho một danh sách.
ToolmakerSteve 8/12/13

9
Nếu hai khóa khác nhau có cùng giá trị thì sao? và chúng xảy ra với cả hai giá trị nhỏ nhất? Làm thế nào bạn có thể làm cho nó trở lại cả hai?
dùng3226932

5
Kỹ thuật này có thể được sử dụng nếu các giá trị dict là danh sách, ví dụ : d={"a":[10, None], "b":[20, None]}, trong đó min được tính từ d [key] [0]?
TrakJohnson

4
Cái này hoạt động ra sao? Loại hàm min đó là gì, tôi nghĩ min () chỉ lấy các giá trị riêng lẻ hoặc liệt kê làm đối số. Làm thế nào để nó lặp qua tất cả các mục trong từ điển?
azureai

2
min()trả về giá trị trong giá trị đầu tiên được sắp xếp khóa chỉ định cách sắp xếp các giá trị. key=d.getcó nghĩa là danh sách sẽ được sắp xếp theo các giá trị của từ điển.
notilas

45

Đây là một câu trả lời thực sự mang lại giải pháp mà OP yêu cầu:

>>> d = {320:1, 321:0, 322:3}
>>> d.items()
[(320, 1), (321, 0), (322, 3)]
>>> # find the minimum by comparing the second element of each tuple
>>> min(d.items(), key=lambda x: x[1]) 
(321, 0)

d.iteritems()Tuy nhiên, việc sử dụng sẽ hiệu quả hơn đối với các từ điển lớn hơn.


3
Thay vì lambda bạn có thể sử dụng operator.itemgetter(1).
Phi

2
thay vì lamda sử dụng d.get
Texom512

Điều này không trả về khóa như đã hỏi, mà là cặp (khóa, giá trị).
Eric O Lebigot

14

Đối với nhiều khóa có giá trị thấp nhất bằng nhau, bạn có thể sử dụng cách hiểu danh sách:

d = {320:1, 321:0, 322:3, 323:0}

minval = min(d.values())
res = [k for k, v in d.items() if v==minval]

[321, 323]

Một phiên bản chức năng tương đương:

res = list(filter(lambda x: d[x]==minval, d))

1
Câu trả lời của bạn rất hữu ích và những người khác có thể đồng ý: xem nhiều bình luận cho vấn đề đó trong câu trả lời được chấp nhận. Tuy nhiên, tôi cần quay lại hai lần để tìm thấy nó: bạn có xem xét đề xuất chỉnh sửa cho câu trả lời được chấp nhận không? Bạn thực sự là bổ sung.
jmon12


6
>>> d = {320:1, 321:0, 322:3}
>>> min(d, key=lambda k: d[k]) 
321

@SilentGhost, @ blob8108: Ôi! Sao chép và dán snafu. Đã sửa bây giờ.
Daniel Stutzbach

Tôi nghĩ rằng giải pháp tốt, nhưng hàm ẩn danh chỉ thêm một lớp cảm ứng: key=d.getlà tốt hơn.
Eric O Lebigot

6

Đối với trường hợp bạn có nhiều khóa tối thiểu và muốn giữ cho nó đơn giản

def minimums(some_dict):
    positions = [] # output variable
    min_value = float("inf")
    for k, v in some_dict.items():
        if v == min_value:
            positions.append(k)
        if v < min_value:
            min_value = v
            positions = [] # output variable
            positions.append(k)

    return positions

minimums({'a':1, 'b':2, 'c':-1, 'd':0, 'e':-1})

['e', 'c']

4

Nếu bạn không chắc chắn rằng bạn không có nhiều giá trị tối thiểu, tôi sẽ đề xuất:

d = {320:1, 321:0, 322:3, 323:0}
print ', '.join(str(key) for min_value in (min(d.values()),) for key in d if d[key]==min_value)

"""Output:
321, 323
"""

3

Chỉnh sửa: đây là câu trả lời cho câu hỏi ban đầu của OP về khóa tối thiểu, không phải câu trả lời tối thiểu.


Bạn có thể lấy các khóa của dict bằng keyshàm và bạn có quyền sử dụng minđể tìm mức tối thiểu của danh sách đó.


Không thực sự xứng đáng với một downvote, vì câu hỏi ban đầu của người đăng không rõ ràng như nó có thể được.
GreenMatt

@ Space_C0wb0y: có lẽ bạn có thể rất tốt khi nhận thấy rằng OP đã chỉnh sửa câu hỏi của mình để có ý nghĩa khác, sau khi tôi trả lời
Eli Bendersky

3

Một cách tiếp cận khác để giải quyết vấn đề của nhiều khóa có cùng giá trị tối thiểu:

>>> dd = {320:1, 321:0, 322:3, 323:0}
>>>
>>> from itertools import groupby
>>> from operator import itemgetter
>>>
>>> print [v for k,v in groupby(sorted((v,k) for k,v in dd.iteritems()), key=itemgetter(0)).next()[1]]
[321, 323]

2

Sử dụng minvới một iterator (để sử dụng python 3 itemsthay vì iteritems); thay vì lambda sử dụng itemgettertoán tử từ, nhanh hơn lambda.

from operator import itemgetter
min_key, _ = min(d.iteritems(), key=itemgetter(1))


1

Tôi đã so sánh cách ba tùy chọn sau thực hiện:

    import random, datetime

myDict = {}
for i in range( 10000000 ):
    myDict[ i ] = random.randint( 0, 10000000 )



# OPTION 1

start = datetime.datetime.now()

sorted = []
for i in myDict:
    sorted.append( ( i, myDict[ i ] ) )
sorted.sort( key = lambda x: x[1] )
print( sorted[0][0] )

end = datetime.datetime.now()
print( end - start )



# OPTION 2

start = datetime.datetime.now()

myDict_values = list( myDict.values() )
myDict_keys = list( myDict.keys() )
min_value = min( myDict_values )
print( myDict_keys[ myDict_values.index( min_value ) ] )

end = datetime.datetime.now()
print( end - start )



# OPTION 3

start = datetime.datetime.now()

print( min( myDict, key=myDict.get ) )

end = datetime.datetime.now()
print( end - start )

Đầu ra mẫu:

#option 1
236230
0:00:14.136808

#option 2
236230
0:00:00.458026

#option 3
236230
0:00:00.824048

0

để tạo một lớp có thứ tự, bạn phải ghi đè 6 hàm đặc biệt, để nó được gọi bởi hàm min ()

các phương thức này __lt__ , __le__, __gt__, __ge__, __eq__ , __ne__theo thứ tự chúng nhỏ hơn, nhỏ hơn hoặc bằng, lớn hơn, lớn hơn hoặc bằng, bằng nhau, không bằng nhau. ví dụ bạn nên thực hiện __lt__như sau:

def __lt__(self, other):
  return self.comparable_value < other.comparable_value

sau đó bạn có thể sử dụng hàm min như sau:

minValue = min(yourList, key=(lambda k: yourList[k]))

Điều này làm việc cho tôi.


0
min(zip(d.values(), d.keys()))[1]

Sử dụng hàm zip để tạo một bộ lặp gồm các bộ chứa các giá trị và khóa. Sau đó bọc nó bằng một hàm tối thiểu lấy tối thiểu dựa trên khóa đầu tiên. Điều này trả về một cặp chứa (giá trị, khóa). Chỉ số của [1] được sử dụng để lấy khóa tương ứng


2
Mặc dù mã này có thể trả lời câu hỏi, cung cấp ngữ cảnh bổ sung về lý do và / hoặc cách mã này trả lời câu hỏi cải thiện giá trị lâu dài của nó.
β.εηablesττ

@ .εηοιτ. tốt hơn?
rajn

-1
# python 
d={320:1, 321:0, 322:3}
reduce(lambda x,y: x if d[x]<=d[y] else y, d.iterkeys())
  321

6
1) Giảm thường chậm hơn itertools. 2) Hầu hết việc thực hiện giảm có thể được thực hiện đơn giản hơn với bất kỳ hoặc tất cả. 3) Tôi là một người phát ngôn khổng lồ cho GvR. 4) Mô-đun toán tử làm cho hầu hết các lambdas đơn giản không cần thiết và lambdas phức tạp nên được định nghĩa là các hàm thực. Có lẽ tôi chỉ sợ lập trình chức năng. ;)
MikeD

@miked: cho tôi biết thêm. những gì gvr và các mô-đun điều hành là gì? bạn có thể gửi liên kết? Tôi có thể biết những người khác, nhưng tôi vẫn chỉ là một trung gian trong python. ý chí học hỏi! :-)
eruciform

GvR là Guido van Rossum, nhà độc tài nhân từ của Python suốt đời. Đây là một bài viết năm năm từ anh ấy giải thích lý do tại sao lisp-isms (bản đồ, bộ lọc, thu nhỏ, lambda) không có nhiều chỗ trong trăn tiến lên, và những lý do đó vẫn còn đúng cho đến ngày nay. Mô-đun toán tử có các thay thế để trích xuất các thành viên : "lambda x: x [1]" so với "itemgetter (1)" là một ký tự dài hơn và có thể mất nhiều thời gian hơn để hiểu. Tôi ra khỏi không gian, nhưng đặt câu hỏi!
MikeD

@miked: muốn cắn miếng táo đầu tiên? stackoverflow.com/questions/3292481/ từ
eruciform

Họ thực sự không cần phải thực hiện lại một cái gì đó được xây dựng trong ( min()).
Eric O Lebigot

-8

Đây có phải là những gì bạn đang tìm kiếm?

d = dict()
d[15.0]='fifteen'
d[14.0]='fourteen'
d[14.5]='fourteenandhalf'

print d[min(d.keys())]

In 'mười bốn'


8
-1: không phải những gì câu hỏi. Bạn đang trả lại giá trị bằng khóa tối thiểu, OP muốn khóa có giá trị tối thiểu
Brian S
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.