我正在尝试编写一个Haskell函数,它接受一个字符串列表,比较列表中的所有字符串,并输出一个长度最长的字符串列表。我想在没有任何预定义函数或导入的情况下执行此操作,我想尝试以递归方式计算出来。例如:
longeststrings["meow","cats","dog","woof"] -> ["meow","cats","woof"]
我知道这是一个愚蠢的例子,但我认为这证明了这一点。
我想做点什么
longeststrings:: [string] -> [string]
longeststrings [] = []
longeststrings [x:xs] = if (x > xs) x:longeststrings[xs]
但我不知道如何只从列表中取出最大的字符串,或删除最小的字符串。我将不胜感激任何帮助。
答案 0 :(得分:5)
您可以轻松跟踪最长的字符串以及该长度值的累加器。
longestStrings :: [String] -> [String]
longestStrings = go [] 0
where
go acc _ [] = acc -- base case
go acc n (x:xs)
| length x > n = go [x] (length x) xs
-- if x is longer than the previously-seen longest string, then set
-- accumulator to the list containing only x, set the longest length
-- to length x, and keep looking
| length x == n = go (x:acc) n xs
-- if x is the same length as the previously-seen longest string, then
-- add it to the accumulator and keep looking
| otherwise = go acc n xs
-- otherwise, ignore it
或者,正如Davislor在评论中正确提到的那样,这可以通过教导辅助函数来确定其最长的长度来实现。
longestStrings :: [String] -> [String]
longestStrings = foldr f []
where
f x [] = [x]
f x yss@(y:_) =
case compare (length x) (length y) of
GT -> [x]
EQ -> x : yss
LT -> yss
答案 1 :(得分:2)
根据要求,这是一个使用和不使用where
的版本。我认为这很好地证明了为什么不使用where
的建议是不好的建议。我认为第一个版本更容易理解。
请记住,功能性编程不是一种修道院的誓言,可以用受虐狂来释放某些关键词。它也不是一个时尚贴士清单(上个赛季where
是所以!)。 “你应该任意避免这种结构,因为它不是'功能'的事情”真的不是它的工作方式。因此,为了这样的提示,你不应该丑化你的代码。
通常是一个好主意,遵循与其他程序员相同的编码风格,这样他们就会发现更容易理解你。 (例如,亚当·斯密巧妙地试图训练你acc
是累加器的通用名称,go
是递归辅助函数的通用名称,它们帮助其他程序员找出他的模式但是实际上Haskell程序员确实使用了where
。
无论如何,代码:
longeststrings :: [String] -> [String]
{- Filters all strings as long as any other in the list. -}
longeststrings = foldr go []
where
go x [] = [x]
go x leaders | newlength > record = [x]
| newlength == record = x:leaders
| otherwise = leaders
where
record = (length . head) leaders
newlength = length x
longestStringsUsingLambda :: [String] -> [String]
longestStringsUsingLambda = foldr
(\x leaders ->
if leaders == [] then [x]
else case compare (length x) (length $ head leaders) of
GT -> [x]
EQ -> x:leaders
LT -> leaders )
[]
main :: IO ()
main = let testcases = [ ["meow","cats","dog","woof"],
["foo","bar","baz"],
["meep","foo","bar","baz","fritz","frotz"]
]
in foldMap print $
map longestStringsUsingLambda testcases
您可以尝试删除let testcases =
...并查看您是否认为这是一项改进。