2011-01-16 71 views
19

Tôi không thể suy nghĩ trong một tư duy chức năng để giải quyết vấn đề này một cách đơn giản cũng có thể hoạt động trong các danh sách rất dài. Nếu bạn có một danh sách như:Cách tìm từ dài nhất trong danh sách?

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

tôi có thể nói những gì mà chiều dài của từ dài nhất là khá đơn giản với:

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

Làm thế nào tôi sẽ sửa đổi báo cáo kết quả trước đó để trả lại chuỗi ba ?

+0

@ Mark Byers Return sự xuất hiện đầu tiên của từ dài nhất. –

Trả lời

37

Sử dụng maximumBy, oncompare bạn có thể viết các biểu hiện như thế này:

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

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

'so sánh \ 'trên \' chiều dài' là 'chiều dài so sánh' trong đó' so sánh' là từ 'Data.Ord'. – Peaker

+0

Thực sự thanh lịch. Giải pháp tốt. –

3

maximumBy(\x -> (x, length x)), fstsnd ở chế độ đơn giản.

12

btw, nếu ai có không sẵn sàng để sử dụng maximumBy, một cách đơn giản sẽ là mô hình trang trí-sort-undecorate/thành ngữ (trong đó hoạt động trong các ngôn ngữ khác như Python hay Scheme cũng):

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

Nhưng kể từ khi tải trọng ban đầu cũng là một phần của các loại-key, kết quả không phải lúc nào sự xuất hiện đầu tiên của từ dài nhất (trong trường hợp này chỉ có một từ có độ dài dài nhất)

+3

Ngay cả với 'maximumBy', điều này rất hữu ích. Hàm 'maximumBy' sẽ tính toán lại độ dài (hoặc bất kỳ hàm so sánh nào đang được sử dụng) của mã thông báo hiện tại dài nhất trong mỗi lần so sánh, trong khi đó trang trí-sắp xếp-undecorate chỉ tính toán độ dài một lần. Phiên bản này là đáng chú ý hơn hiệu quả ngay cả với đầu vào có kích thước khiêm tốn. Tất nhiên, nếu bạn đang sử dụng danh sách có độ dài bất kỳ, có thể bạn không nên sử dụng danh sách. –

+0

@ John nếu bạn chỉ thực hiện một lần truyền qua một luồng dữ liệu, một danh sách có độ dài bất kỳ là hoàn toàn ổn. Bây giờ, các chuỗi khác ... – sclv

+0

@John, cảm ơn vì đã chỉ ra vấn đề 'tối đa (By)' đánh giá lại 'max', điều mà tôi không biết và làm tôi ngạc nhiên một chút (thực hiện' tối đa' bằng cách đơn giản 'foldl1 max' là không có nghi ngờ thanh lịch tuy nhiên) – hvr

8

Chức năng này (hoặc thậm chí cả thư viện) dường như không nổi tiếng, nhưng Haskell thực sự có một mô-đun gọi là Data.Ord có chứa hàm comparing. như sử dụng Data.Function.on trong câu trả lời hàng đầu, ngoại trừ mã kết thúc thành ngữ hơn.

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" 

Mã thực tế đọc như tiếng Anh. "Nhận tối đa bằng cách so sánh độ dài".

+0

Những người khác không đồng ý và nghĩ rằng 'so sánh' là một trường hợp đặc biệt ngớ ngẩn. Tôi không quan tâm, bản thân mình, nhưng tôi đã nghe những người có kinh nghiệm phàn nàn về nó. – dfeuer

1

Để tính length a, bạn cần phải duyệt qua toàn bộ danh sách a. Trong trường hợp sử dụng cụ thể này, bạn chỉ quan tâm đến từ dài nhất, và không chính xác là bao lâu, vì vậy bạn có thể viết một hàm chỉ đi xa đến mức cần thiết trong mỗi danh sách để xác định cái nào dài nhất. Điều này có thể giúp bạn tiết kiệm một số xử lý:

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

Bạn không cần nhiều đối số để 'go'. Chỉ cần sử dụng các tên khác nhau và tham khảo những cái trong phạm vi bên ngoài. 'longestWord a b = go a b, đi một '_ = a ...' – dfeuer

0
foldl (\accmax xs -> if length accmax < length xs then xs else accmax) [] ["one", "two", "three", "four", "five"] 
Các vấn đề liên quan