2011-01-16 14 views
19

Ich kann meinen Verstand nicht in einer funktionalen Denkweise dazu bringen, dieses Problem auf eine einfache Weise zu lösen, die auch für sehr lange Listen funktionieren könnte. Wenn Sie eine Liste wie haben:Wie finde ich das längste Wort in der Liste?

["one", "two", "three", "four", "five"] 

kann ich sagen, was die Länge des längsten Wortes ist ziemlich einfach mit:

maximum $ map length ["one", "two", "three", "four", "five"] 

Wie würde ich die vorherige Anweisung ändern Sie die Zeichenfolge zurück drei ?

+0

@ Mark Byers Rückkehr das erste Auftreten des längsten Wortes. –

Antwort

37

Mit maximumBy, on und compare Sie den Ausdruck wie folgt schreiben kann:

import Data.List (maximumBy) 
import Data.Function (on) 

maximumBy (compare `on` length) ["one", "two", "three", "four", "five"] 
+6

'compare \' on \ 'length' ist 'comparing length', wobei' comparing' aus 'Data.Ord' steht. – Peaker

+0

Wirklich elegant. Nette Lösung. –

3

maximumBy(\x -> (x, length x)), , und snd in einer einfachen Zusammensetzung tun den Trick.

12

btw, wenn man hatte keine ready-to-use maximumBy, eine einfache Möglichkeit, die deco-Art-undecorate Muster wäre/Idiom (die auch in anderen Sprachen wie Python oder Schema funktioniert):

snd $ maximum $ map (\x -> (length x, x)) ["one", "two", "three", "four", "five"] 

Aber da die ursprüngliche Nutzlast auch einen Teil des Art-Schlüssels ist, ist das Ergebnis nicht immer das erste Auftreten des längsten Wortes (in diesem Fall gab es nur ein Wort mit der längsten Länge)

+3

Auch mit 'maximumBy' ist das nützlich. Die "maximumBy" -Funktion berechnet die Länge (oder die Vergleichsfunktion, die gerade verwendet wird) des längsten aktuellen Tokens bei jedem Vergleich neu, während decorate-sort-undecorate die Länge nur einmal berechnet. Diese Version ist deutlich effizienter, selbst bei kleinen Eingängen. Wenn Sie Listen beliebiger Länge verwenden, sollten Sie natürlich keine Listen verwenden. –

+0

@John Wenn Sie nur einen einzigen Durchlauf über einen Datenstrom machen, ist eine Liste beliebiger Länge völlig in Ordnung. Jetzt Strings auf der anderen Seite ... – sclv

+0

@John, danke für das Hinweis auf das Thema 'Maximum (By)' Neubewertung 'max', die ich nicht bewusst war und mich ein wenig überrascht (Umsetzung' Maximum' einfach "foldl1 max" ist doch ohne Zweifel elegant :) – hvr

8

Diese Funktion (oder sogar Bibliothek) scheint nicht gut bekannt zu sein, aber Haskell hat tatsächlich ein Modul namens Data.Ord, das die Funktion comparing enthält, die fast ist wie mit Data.Function.on in der oberen Antwort, außer der Code endet mehr idiomatische.

g>import Data.Ord 
g>import Data.List 
g>let getLongestElement = maximumBy (comparing length) 
getLongestElement :: [[a]] -> [a] 
g>getLongestElement ["one", "two", "three", "four", "five"] 
"three" 

Der Code liest sich praktisch wie Englisch. "Holen Sie sich das Maximum, indem Sie die Länge vergleichen."

+0

Andere stimmen nicht zu und denken, "Vergleichen" sei ein alberner Sonderfall. Es ist mir egal, aber ich habe erfahrene Leute gehört, die sich darüber beschweren. – dfeuer

1

Um length a zu berechnen, müssen Sie die gesamte Liste durchlaufen a. In diesem speziellen Anwendungsfall interessiert Sie nur das längste Wort und nicht genau, wie lange sie sind. Sie können also eine Funktion schreiben, die nur so weit geht, wie sie in jeder Liste benötigt wird, um zu bestimmen, welche die längste ist. Dies kann Sie einige Verarbeitung sparen:

module Main where 

main = putStrLn $ longestWordInList ["one", "two", "three", "four"] 

longestWordInList = go "" 
    where go result [] = result 
     go result (x:xs) = let result' = longestWord result x in 
           result' `seq` go result' xs 

longestWord a b = go a b a b 
    where go a _ _ [] = a 
     go _ b [] _ = b 
     go a b (_:as) (_:bs) = go a b as bs 
+0

Sie brauchen nicht so viele Argumente zu "gehen". Verwenden Sie einfach andere Namen und beziehen Sie sich auf die im äußeren Bereich. 'longestWord a b = geh 'a b wo geh' a '_ = a ...' – dfeuer

0
foldl (\accmax xs -> if length accmax < length xs then xs else accmax) [] ["one", "two", "three", "four", "five"] 
Verwandte Themen