2012-03-31 37 views
6

Hãy v là một danh sách các sốTìm chỉ số của nguyên tố tối đa từ danh sách Python

v = [3,5,2,4,8,6,1] 

Tại sao đoạn mã sau để tìm các phần tử tối đa và chỉ số của nó đưa ra một lỗi? (đối tượng 'int' không thể ghi được)

reduce(lambda x,y: max(x[1],y[1]), enumerate(v)) 

P.S. Tôi biết có nhiều cách khác để làm điều đó, như dưới đây nhưng tôi muốn hiểu tại sao cách trước đó không hoạt động.

max(enumerate(v), key= lambda x: x[1]) 

Epilogue

Simeon chỉ ra rằng mã của tôi là thực sự sai nguyên nhân lambda nên đã trở về một tuple, không phải là một số. Hiểu được điều này, mã của tôi có thể dễ dàng cố định theo cách sau:

reduce(lambda x,y: x[1]<y[1] and y or x, enumerate(v)) 

đó là, bằng cách này, chậm hơn so với

max(enumerate(v), key= lambda x: x[1]) 
+0

Tôi vô tình bỏ phiếu để đóng bản sao. Nó không phải là một bản sao, mặc dù. –

Trả lời

6

Bạn đang hỏi tại sao sau không làm việc:

 
reduce(lambda x,y: max(x[1],y[1]), enumerate(v)) 

Hãy xem: đầu vào của bạn là enumerate(v) đó lặp trên các yếu tố sau:

 
[(0, 3), (1, 5), (2, 2), (3, 4), (4, 8), (5, 6), (6, 1)] 

Bạn có ý định giảm bớt các yếu tố này với hàm lambda x,y: max(x[1],y[1]). Theo the docs, giảm có một chức năng như đầu vào được áp dụng cho hai yếu tố của iterable. Điều đó có nghĩa là nó làm giảm hai phần tử và trả về một giá trị, đó là một trong các đối số của lời gọi tiếp theo để giảm.

Điều đó có nghĩa là xy là bộ dữ liệu. Để làm việc trên, giá trị trả về của hàm lambda cần phải là một bộ dữ liệu một lần nữa vì nó được sử dụng một lần nữa trong lần giảm tiếp theo. Nhưng bạn đang trả lại một số nguyên, kết quả là max. Đó là lý do tại sao bạn nhận được một lỗi: "'int' đối tượng không phải là subscriptable" bởi vì x[1] không hoạt động khi x là một số nguyên.

+0

Cảm ơn! Tôi đang tìm kiếm lỗi tinh tế và tôi không thể nhìn thấy cái lớn. – mmj

2

công trình Làm thế nào giảm khoảng 30%:

# type annotations: 
# reduce(lambda X,X:X, [X,X..]) -> X 

#    SAME <-- result 
#   ↗ ↖ 
#  SAME SAME] 
#  ↗ ↖ 
# SAME SAME, 
#  ↗ ↖ 
# [SAME, SAME, 

>>> reduce(lambda a,b:[a,b], [1,2,3,4]) 
[[[1, 2], 3], 4] 

Đây là cách giảm hạt giống (còn gọi là gấp trái) hoạt động:

# type annotations: 
# reduce(lambda REDU,ELEM:REDU, [ELEM,ELEM..], seed=REDU) -> REDU 

#    REDU <-- result 
#   ↗ ↖ 
#  REDU ELEM] 
#   ↗ ↖ 
#  REDU ELEM, 
#  ↗ ↖ 
# REDU ELEM, 
#  ↗ ↖ 
# REDU [ELEM, 

>>> reduce(lambda a,b:[a,b], [1,2,3,4], 'seed') 
[[[['seed', 1], 2], 3], 4] 

Bạn muốn:

maxValue,maxIndex = reduce(
    lambda p1,p2: max(p1,p2), 
    ((x,i) for i,x in enumerate(yourList)) 
) 

Điều quan trọng cần chú ý về reduceloại. * Khi bạn sử dụng giảm (...) với giá trị hạt giống (được gọi là fold bằng các ngôn ngữ khác), loại trả về sẽ là loại của hạt giống. * Khi bạn sử dụng reduce bình thường, nó bỏ qua phần tử hạt giống. Điều này làm việc tuyệt vời nếu tất cả các phần tử trong danh sách của bạn cùng loại (ví dụ, bạn có thể reduce(operator.mul, [1,2,3]) hoặc reduce(operator.add, [1,2,3]) tốt, vì loại đầu ra giảm (int) giống với loại đầu vào chưa được tạo (hai int)). Tuy nhiên loại trả về sẽ giống với loại phần tử của danh sách.

Nếu các phần tử của bạn có nhiều loại khác nhau, bạn cần phải sử dụng hàm reduce (...) trong fold -mode (tức là với hạt giống với ngữ nghĩa phù hợp). (Cách khác là trường hợp đặc biệt lambda của bạn (rất xấu xí).)

Rõ ràng hơn, kiểu trả về dự định của bạn là một bộ (phần tử tối đa và chỉ mục của nó hoặc ngược lại). Tuy nhiên chức năng giảm của bạn là loại tuple,tuple -> int. Điều này không thể làm việc vì nó vi phạm hợp đồng làm giảm nhu cầu của chức năng của bạn.

Các vấn đề liên quan