简体   繁体   English

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

[英]How to compare multiple strings within in the same list in Haskell

I am trying to write a Haskell function that takes in a list of strings, compares all the strings in the list, and outputs a list of strings that are of the longest length. 我正在尝试编写一个Haskell函数,它接受一个字符串列表,比较列表中的所有字符串,并输出一个长度最长的字符串列表。 I want to do this without any predefined functions or imports, I want to try and figure it out all recursively. 我想在没有任何预定义函数或导入的情况下执行此操作,我想尝试以递归方式计算出来。 For example: 例如:

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

I know it is a silly example, but I think it proves the point. 我知道这是一个愚蠢的例子,但我认为这证明了这一点。

I want to do something like 我想做点什么

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

But I don't know how to only take the largest size strings out of the list, or remove the smallest ones. 但我不知道如何只从列表中取出最大的字符串,或删除最小的字符串。 I would appreciate any help. 我将不胜感激任何帮助。

you could trivially keep track of the longest length string and an accumulator of values of that length. 你可以轻而易举地跟踪最长的字符串和一个长度值的累加器。

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

or, as Davislor rightly mentions in the comments, this can be implemented as a fold by teaching the helper function to determine its own longest length 或者,正如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

As requested, here's a version with and without the use of where . 根据要求,这是一个使用和不使用where I think this is a good demonstration of why the advice not to use where is bad advice. 我认为这是一个很好的证明,为什么建议不要使用where是不好的建议。 I think the first version is a lot easier to understand. 我认为第一个版本更容易理解。

Keep in mind, functional programming isn't a monastic vow to forswear certain keywords out of masochism. 请记住,函数式编程不是一个修道院的誓言,可以用受虐狂来释放某些关键词。 Nor is it a checklist of fashion tips ( where is so last season!). 它也不是时尚尖端的清单( where如此的最后一个赛季!)。 “You should avoid that construct arbitrarily because it's not the 'functional' thing to do” really is not how it works. “你应该任意避免这种结构,因为它不是'功能'的事情”真的不是它的工作方式。 So you shouldn't uglify your code for the sake of a tip like that. 所以你不应该为了这样的提示而丑化你的代码。

It is often a good idea to follow the same coding style as other programmers so they will find it easier to understand you. 它往往遵循同样的编码风格为其他程序员所以他们会发现很容易理解,你是个好主意。 (For example, Adam Smith was subtly trying to train you that acc is a common name for an accumulator and go a common name for a recursive helper function, and they help other programmers figure out the pattern he's using.) But in fact Haskell programmers do use where , a lot. (例如,亚当·斯密被巧妙地努力训练你, acc是蓄能器的通用名称,并go了递归辅助功能的通用名称,并帮助其他的程序员弄清楚他使用的模式。)但实际上Haskell的程序员确实where很多where使用。

Anyway, the code: 无论如何,代码:

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

You can try eliminating the let testcases = ... and see if you consider that an improvement. 您可以尝试删除let testcases = ...并查看您是否认为这是一项改进。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM