2011-01-16 41 views
19

Non riesco a pensare a una mentalità funzionale per risolvere questo problema in un modo semplice che potrebbe funzionare anche per elenchi molto lunghi. Se si dispone di una lista come:Come trovare la parola più lunga in elenco?

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

posso dire ciò che la lunghezza della parola più lunga è piuttosto semplice, con:

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

Come faccio a modificare l'istruzione precedente per restituire la stringa di tre ?

+0

@ Mark Byers Ritorna la prima occorrenza della parola più lunga. –

risposta

37

Utilizzando maximumBy, on e compare è possibile scrivere l'espressione in questo modo:

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

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

'compare \' su \ 'length' è' comparando length' dove 'comparing' è from' Data.Ord'. – Peaker

+0

Davvero elegante. Bella soluzione –

3

, fst e snd in una composizione semplice fanno il trucco.

12

btw, se uno non avevano pronto per l'uso maximumBy, un modo semplice sarebbe il modello di decorare-sort-undecorate/linguaggio (che funziona anche in altri linguaggi come Python o Scheme pure):

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

Ma poiché il payload originale è anche parte del-chiave di ordinamento, il risultato non è sempre la prima occorrenza della parola più lunga (in questo caso c'era solo una parola con la lunghezza più lunga)

+3

Anche con 'maximumBy', questo è utile. La funzione 'maximumBy' ricalcolerà la lunghezza (o qualsiasi altra funzione di confronto utilizzata) del token corrente più lungo ad ogni confronto, mentre decor-sort-undecorate calcola solo la lunghezza una volta. Questa versione è notevolmente più efficiente anche con input di dimensioni modeste. Ovviamente, se stai usando elenchi di qualsiasi lunghezza, probabilmente non dovresti usare le liste. –

+0

@John se stai facendo un singolo passaggio su un flusso di dati, un elenco di qualsiasi lunghezza è perfettamente a posto. Ora stringhe d'altra parte ... – sclv

+0

@John, grazie per aver segnalato il problema di 'maximum (By)' rivalutando 'max', di cui non ero a conoscenza e mi ha sorpreso un po '(implementando' maximum' semplicemente 'foldl1 max' è senza dubbio elegante tuttavia) – hvr

8

Questa funzione (o anche la libreria) non sembra essere ben nota, ma Haskell ha in realtà un modulo chiamato Data.Ord che contiene la funzione comparing che è quasi come usare Data.Function.on nella risposta superiore, tranne che il codice finisce per essere più idiomatico.

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" 

Il codice praticamente si legge come l'inglese. "Ottieni il massimo confrontando la lunghezza."

+0

Altri non sono d'accordo e pensano che "confrontare" sia un caso sciocco. Non mi interessa, me stesso, ma ho sentito persone con esperienza lamentarsi di questo. – dfeuer

1

Per calcolare length a, è necessario attraversare l'intero elenco a. In questo particolare caso d'uso, sei solo preoccupato per la parola più lunga, e non esattamente per quanto tempo sono, quindi puoi scrivere una funzione che va solo nella misura in cui è necessaria in ciascuna lista per determinare quale è la più lunga. Questo può risparmiare un po 'di elaborazione:

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

Non hai bisogno di così tanti argomenti per 'andare'. Basta usare nomi diversi e fare riferimento a quelli in ambito esterno. 'longestWord a b = go a b dove go a '_ = a ...' – dfeuer

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