如何比较Haskell中同一列表中的多个字符串

时间:2018-02-09 20:58:49

标签: string list haskell recursion functional-programming

我正在尝试编写一个Haskell函数,它接受一个字符串列表,比较列表中的所有字符串,并输出一个长度最长的字符串列表。我想在没有任何预定义函数或导入的情况下执行此操作,我想尝试以递归方式计算出来。例如:

    longeststrings["meow","cats","dog","woof"] -> ["meow","cats","woof"]

我知道这是一个愚蠢的例子,但我认为这证明了这一点。

我想做点什么

    longeststrings:: [string] -> [string]
    longeststrings []          = []
    longeststrings [x:xs]      = if (x > xs) x:longeststrings[xs]

但我不知道如何只从列表中取出最大的字符串,或删除最小的字符串。我将不胜感激任何帮助。

2 个答案:

答案 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 = ...并查看您是否认为这是一项改进。