2013-02-01 14 views
7

Co jest bardziej pythonic sposobem na uzyskanie długość najdłuższego słowa:Długość najdłuższego słowa w liście

len(max(words, key=len))

czyli

max(len(w) for w in words)

Albo coś innego .. ? words to lista ciągów. Zauważyłem, że muszę to robić często i po ustaleniu czasu z kilkoma różnymi wielkościami próbek, pierwszy sposób wydaje się być konsekwentnie szybszy, mimo że wydaje się mniej wydajny pod względem wartości nominalnej (nadmiarowość len nazywana dwukrotnie wydaje się nie mieć znaczenia - robi więcej zdarza się w kodzie C w tym formularzu?).

+0

@isedev że dam słowo, a nie długość słowa –

+2

osobiście wolę to drugie, wygląda ładniejsze – Wolph

+4

'' DŁ (max (słowa, key = LEN)) '' jest dobry ponieważ służy jako * Och, zapomniałem '' max'' wziął klucz jako argument. * Przypomnienie dla wet-ware. – sotapme

Odpowiedz

5

myślę oba są OK, ale myślę, że jeśli prędkość jest duża uwagę, że max(len(w) for w in words) jest najbardziej czytelny.

Kiedy patrzyłem na nich, zajęło mi więcej czasu, aby dowiedzieć się, co robił len(max(words, key=len)), i nadal byłem w błędzie, dopóki nie pomyślałem o tym więcej. Kod powinien być od razu oczywisty, chyba że istnieje ku temu dobry powód.

Z innych wpisów (i moich własnych testów) jasno wynika, że ​​ten mniej czytelny jest szybszy. Ale to nie tak, że każdy z nich jest wolny od psa. A jeśli kod nie znajduje się na krytycznej ścieżce, nie warto się tym przejmować.

Ostatecznie, myślę, że bardziej czytelny jest bardziej Pythoniczny.

Jako jeden z niewielu przypadków, w których Python 2 jest znacznie szybszy niż Python 3 dla tego samego zadania.

+0

W moich testach 3.3.0 pokonało 2.7.2 dla każdej wersji, którą mogłem wymyślić. (Zobacz moją odpowiedź na oczywiste.) Aktualizacja – abarnert

+0

: Właściwie, jeśli uruchomię je zarówno w trybie 32-bitowym, 3.3.0 jest znacznie wolniej. Ale prawie wszystko wydaje się wolne w wersjach 32-bitowych 3.2 lub 3.3, przynajmniej na komputerach Mac, więc nie sądzę, żeby było coś konkretnego w tym przypadku. – abarnert

+0

@ABarnert: Interesujące. Uruchomiłem je w trybie 64-bitowym w systemie Linux. Jednym z nich był Python 2.7.3 i inny 3.3.0. Używałem '/ usr/share/dict/words' jako listy słów. Osiągałem prędkości 88 ms w porównaniu z 66 ms. Być może jest to mój wybór długiej listy słów, która zrobiła różnicę. – Omnifarious

1

Powiedziałbym

len(max(x, key=len)) 

wygląda całkiem dobrze, ponieważ wykorzystują argument słowa kluczowego (key) z wbudowanym (max) z wbudowanym (len). Więc w zasadzie max(x, key=len) dostaniesz prawie odpowiedź. Ale żaden z twoich wariantów kodu nie wygląda mi szczególnie nieprecyzyjnie.

+1

Ale * dlaczego *? Czy istnieje jakiś powód? – arshajii

+0

@ A.R.S .: Dodano krótki, dobrze ... subiektywny powód. – miku

8

Chociaż:

max(len(w) for w in words) 

robi rodzaju „czytać” łatwiejsze - masz napowietrznej generatora.

Podczas:

len(max(words, key=len)) 

może zoptymalizować precz z kluczem używając poleceń wbudowanych i od len jest zwykle bardzo skuteczne na smyczki op, będzie szybciej ...

+1

W związku z tym - nie mogę powiedzieć, który jest bardziej "Pythoniczny" - lubię jedno i drugie, ale dla kogoś, kto nie zna się na użyciu 'max' z' kluczem ', być może ten pierwszy będzie bardziej grokowalny –

0

Tylko dla informacji za pomocą 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 

Po prostu zaktualizowano o więcej słów, aby zademonstrować punkt/komentarz Omeny.

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

Jak na liście Zwiększa się rozbieżność. – Omnifarious

3

Jeśli przepisujesz wyrażenie generatora jako wywołanie map (lub, dla 2.x, imap):

max(map(len, words)) 

... to faktycznie nieco szybciej niż w wersji kluczowej, nie wolniej.

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 

Jabłko 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 

myślę, że to bardziej pythonic niż wersja key, z tego samego powodu genexp jest.

Można argumentować, czy jest to wersja pythonic, jak wersja genexp. Niektórzy ludzie lubią map/filter/reduce/itp .; niektórzy nienawidzą ich; moim osobistym odczuciem jest to, że kiedy próbujesz odwzorować funkcję, która już istnieje i ma ładne imię (to znaczy, że nie musisz tego robić),lub partial) jest ładniejsza, ale YMMV (szczególnie jeśli masz na imię jest Guido).

Ostatni punkt:

zwolnienie od len nazywany jest dwa razy wydaje się nie ma znaczenia - nie więcej zdarzyć w kodzie C w tej formie?

Pomyśl o tym tak: już dzwonisz pod numer len N razy. Wywoływanie go w wersji N+1 jest raczej mało prawdopodobne, aby coś zmienić, w porównaniu do wszystkiego, co musisz zrobić N razy, chyba że masz mały numer ogromny ciągów.

+0

'max (mapa (len, words)) 'jest również całkiem czytelny i oczywisty. Więc dostaje mój głos. – Omnifarious

+0

@Omnifarious: Jest czytelny i oczywisty dla mnie i dla ciebie ... ale może nie dla wszystkich. Dodałem akapit na ten temat. – abarnert

-1

wiem, że to już rok, ale teraz Neverthless, wpadłem na to:

„” 'Napisz find_longest_word function(), która pobiera listę słów i zwraca długość najdłuższego jednego. ''

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) 
Powiązane problemy