2013-02-01 65 views
7

là gì cách pythonic hơn nhận được độ dài của từ dài nhất:Chiều dài của từ dài nhất trong một danh sách

len(max(words, key=len))

Hoặc:

max(len(w) for w in words)

Hoặc .. cái gì khác ? words là danh sách các chuỗi. Tôi thấy rằng tôi cần phải thực hiện điều này thường xuyên và sau khi định thời với một vài kích thước mẫu khác nhau, cách đầu tiên có vẻ nhanh hơn, mặc dù dường như không hiệu quả về mặt giá trị (sự thừa của len được gọi hai lần có vẻ không quan trọng - làm nhiều hơn xảy ra trong mã C trong biểu mẫu này?).

+0

@isedev mà sẽ cung cấp cho các văn bản, không phải là chiều dài của từ –

+2

Cá nhân tôi thích thứ hai, trông đẹp hơn – Wolph

+4

'' len (max (từ, key = len)) '' là tốt bởi vì nó phục vụ như là một * Oh tôi quên '' max'' mất chìa khóa như là một đối số. * nhắc nhở cho các đồ ướt. – sotapme

Trả lời

5

Tôi nghĩ cả hai đều ổn, nhưng tôi nghĩ rằng trừ khi tốc độ là một cân nhắc lớn mà max(len(w) for w in words) là dễ đọc nhất.

Khi tôi nhìn vào chúng, tôi mất nhiều thời gian hơn để tìm hiểu xem len(max(words, key=len)) đang làm gì và tôi vẫn sai cho đến khi tôi nghĩ về nó nhiều hơn. Mã nên được ngay lập tức rõ ràng trừ khi có một lý do chính đáng cho nó không được.

Rõ ràng từ các bài đăng khác (và các bài kiểm tra của riêng tôi) rằng bài đăng ít đọc hơn sẽ nhanh hơn. Nhưng nó không giống như một trong số họ là con chó chậm. Và trừ khi mã trên một con đường quan trọng, nó không đáng lo ngại.

Cuối cùng, tôi nghĩ có thể đọc được nhiều hơn là Pythonic.

Ngoài ra, đây là một trong số ít trường hợp trong đó Python 2 đáng chú ý là nhanh hơn Python 3 cho cùng một tác vụ.

+0

Trong bài kiểm tra của tôi, 3.3.0 đánh bại 2.7.2 cho mỗi phiên bản tôi có thể đưa ra. (Xem câu trả lời của tôi cho những người rõ ràng.) – abarnert

+0

Cập nhật: Trên thực tế, nếu tôi chạy cả hai trong chế độ 32-bit, 3.3.0 là chậm hơn đáng kể. Nhưng sau đó hầu như tất cả mọi thứ có vẻ chậm trong 32-bit 3,2 hoặc 3,3, ít nhất là trên máy Mac, vì vậy tôi không nghĩ rằng có bất cứ điều gì cụ thể cho trường hợp này. – abarnert

+0

@abarnert: Thú vị. Tôi chạy cả hai trong chế độ 64-bit trên một hệ thống Linux. Một là Python 2.7.3 và 3.3.0 khác. Tôi đã sử dụng '/ usr/share/dict/words' làm danh sách từ. Tôi đã nhận được tốc độ 88ms so với 66ms. Có lẽ đó là lựa chọn của tôi về một danh sách từ dài tạo ra sự khác biệt. – Omnifarious

1

Tôi muốn nói

len(max(x, key=len)) 

trông khá tốt vì bạn sử dụng một đối số từ khóa (key) của một built-in (max) với một built-in (len). Vì vậy, về cơ bản max(x, key=len) giúp bạn gần như câu trả lời. Nhưng không có biến thể mã nào của bạn trông đặc biệt là không thiên vị đối với tôi.

+1

Nhưng * tại sao *? Có lý do gì không? – arshajii

+0

@ A.R.S .: Đã thêm một lý do chủ quan, ngắn gọn, .... – miku

8

Mặc dù:

max(len(w) for w in words) 

làm loại "đọc" dễ dàng hơn - bạn đã có những phí của một máy phát điện.

Trong khi:

len(max(words, key=len)) 

thể tối ưu hóa đi với phím sử dụng dựng sẵn và từ len là bình thường một op rất hiệu quả cho các chuỗi, sẽ là nhanh hơn ...

+1

Điều đó đang được nói - Tôi không thể nói đó là "Pythonic" hơn - tôi thích cả hai, nhưng đối với một người không quen với việc sử dụng 'max' với' key' có lẽ trước đây sẽ là ngay lập tức grokkable –

0

Chỉ cần để biết sử dụng ipython %timeit

In [150]: words 
Out[150]: ['now', 'is', 'the', 'winter', 'of', 'our', 'partyhat'] 

In [148]: %timeit max(len(w) for w in words) 
100000 loops, best of 3: 1.87 us per loop 

In [149]: %timeit len(max(words, key=len)) 
1000000 loops, best of 3: 1.35 us per loop 

Chỉ cần cập nhật với nhiều từ hơn để chứng minh @ Omnifarious's point/comment.

In [160]: words = map(string.rstrip, open('/usr/share/dict/words').readlines()) 

In [161]: len(words) 
Out[161]: 235886 

In [162]: %timeit max(len(w) for w in words) 
10 loops, best of 3: 44 ms per loop 

In [163]: %timeit len(max(words, key=len)) 
10 loops, best of 3: 25 ms per loop 
+0

Như danh sách được lâu hơn sự khác biệt được lớn hơn. – Omnifarious

3

Nếu bạn viết lại biểu thức trình tạo dưới dạng cuộc gọi map (hoặc, cho 2.x, imap):

max(map(len, words)) 

… nó thực sự nhanh hơn một chút so với phiên bản chính, không chậm hơn.

python.org 64-bit 3.3.0:

In [186]: words = ['now', 'is', 'the', 'winter', 'of', 'our', 'partyhat'] * 100 
In [188]: %timeit max(len(w) for w in words) 
%10000 loops, best of 3: 90.1 us per loop 
In [189]: %timeit len(max(words, key=len)) 
10000 loops, best of 3: 57.3 us per loop 
In [190]: %timeit max(map(len, words)) 
10000 loops, best of 3: 53.4 us per loop 

của Apple 64-bit 2.7.2:

In [298]: words = ['now', 'is', 'the', 'winter', 'of', 'our', 'partyhat'] * 100 
In [299]: %timeit max(len(w) for w in words) 
10000 loops, best of 3: 99 us per loop 
In [300]: %timeit len(max(words, key=len)) 
10000 loops, best of 3: 64.1 us per loop 
In [301]: %timeit max(map(len, words)) 
10000 loops, best of 3: 67 us per loop 
In [303]: %timeit max(itertools.imap(len, words)) 
10000 loops, best of 3: 63.4 us per loop 

Tôi nghĩ đó là hơn pythonic so với phiên bản key, với cùng lý do genexp là.

Có thể tranh cãi cho dù đó là pythonic như phiên bản genexp. Một số người yêu thích số map/filter/reduce/etc; một số ghét họ; cảm giác cá nhân của tôi là khi bạn đang cố gắng ánh xạ một hàm đã tồn tại và có một tên đẹp (nghĩa là, bạn không cần phải lambda hoặc partial), map đẹp hơn, nhưng YMMV (đặc biệt là nếu tên của bạn) là Guido).

Một điểm cuối cùng:

sự dư thừa của len được gọi hai lần dường như không thành vấn đề - không xảy ra hơn trong mã C theo hình thức này?

Hãy nghĩ về điều này như sau: Bạn đã gọi số len N lần. Gọi nó là N+1 lần thay vì hầu như không có khả năng tạo sự khác biệt, so với bất cứ điều gì bạn phải làm N lần, trừ khi bạn có số nhỏ số lớn.

+0

'max (map (len, từ)) 'cũng khá dễ đọc và rõ ràng. Vì vậy, nó được bỏ phiếu của tôi. – Omnifarious

+0

@Omnifarious: Đó là dễ đọc và rõ ràng đối với tôi, và với bạn ... nhưng có thể không cho tất cả mọi người. Tôi đã thêm một đoạn về điều đó. – abarnert

-1

Tôi biết nó được một năm nay nhưng neverthless, tôi đến với điều này:

'' 'Viết một hàm find_longest_word() mà phải mất một danh sách các từ và trả về chiều dài của dài nhất.' ''

a = ['mamao', 'abacate', 'pera', 'goiaba', 'uva', 'abacaxi', 'laranja', 'maca'] 

def find_longest_word(a): 

    d = [] 
    for c in a: 
     d.append(len(c)) 
     e = max(d) #Try "min" :D 
    for b in a: 
     if len(b) == e: 
      print "Length is %i for %s" %(len(b), b) 
Các vấn đề liên quan