Haskell列表中最长的连续元素系列

时间:2016-12-30 01:06:17

标签: haskell recursion functional-programming

我是函数式编程的新手,还有语言haskell。我试图根据谓词函数确定列表中最长的连续元素系列的长度。该功能如下所示:

 longestSequence :: (a -> Bool) -> [Int] -> Int

当我这样称呼时:

 longestSequence (\x -> x >= 10) [1,44,33,22,2,3,55,66,66,77,88,99]

它应该给我解决方案6

我的解决方案是:

longestSequence :: (a -> Bool) -> [a] -> Int
longestSequence p [] = 0
longestSequence p (x:xs) 
  | (p x) = 1 + (longestSequence p xs)
  | otherwise = longestSequence p xs

我如何解决这个问题的任何提示或想法?

3 个答案:

答案 0 :(得分:5)

尝试分解较小的子问题。对于这个例子,一般策略可能是这样的:

  1. 如果相应的条目满足谓词,则将给定列表转换为[Bool]列表,其中条目为True。那就是写一个函数(Int -> Bool) -> [Int] -> [Bool]
  2. 分组连续的TrueFalse值。那就是写一个函数[Bool] -> [[Bool]]。您可能需要查看Data.List.group
  3. 过滤掉False群组:[[Bool]] -> [[Bool]]
  4. 对于每个内部列表计算其长度。 [[Bool]] -> [Int]
  5. 找出这些长度的最大值:[Int] -> Int
  6. 然后你只需要编写这些功能就完成了。对于1.和4.您将需要使用函数map :: (a -> b) -> [a] -> [b]。如果您已经知道map,请使用它。如果你不这样做,我建议你自己写一下。

    我提供的函数的某些类型签名过于具体。也许试着在可能的地方稍微概括一下。

答案 1 :(得分:3)

在警卫中,p xotherwise部分都存在问题。

(p x) = 1 + (longestSequence p xs)并非总是如此,如果x的下一个元素不能保持预测p,则无法添加1 {/ p> 如果当前最长的序列比剩余的序列长

,则

otherwise = longestSequence p xs不成立

可能的解决方法是保持最大长度和当前长度

longestSequence :: (a -> Bool) -> [a] -> Int
longestSequence p x = ls x 0 0
  where
    ls [] mx cur = max mx cur
    ls (x:xs) mx cur
        | p x = ls xs mx (cur+1)
        | otherwise = ls xs (max mx cur) 0

答案 2 :(得分:1)

您经常可以使用比递归更简单的fold,在这种情况下,我们希望使用scanl,就像foldl一样,除了它保留整个列表。

以下内容遍历列表,递增与谓词匹配的每个项目的计数。如果找到一个不匹配的,它会将计数重置为零。最后,它找到结果列表的最大值。

longestSequence p = maximum . scanl (\count x -> if (p x) then count + 1 else 0) 0

对于[1,44,33,22,2,3,55,66,66,77,88,99]的示例输入和(\x -> x >= 10)的谓词,scanl将生成[0,0,1,2,3,0,0,1,2,3,4,5,6]的输出。取这个列表的最大值给出6,你可以看到最大值出现在输入的末尾,而且列表中的谓词也不匹配。

顺便说一句,我全心全意地同意将问题分解成小部分的jpath。我已经看到人们通过使用元组填充fold参数内的max计算来解决\count的类似问题,但这使得阅读更加困难。顺便说一句,这也是像你这样的单功能递归解决方案很难解决的问题。一次跟踪太多,所以很难看到在重置为零的位置和方式。