使用递归将列表分解为子列表

2024-04-05

我正在尝试使用类型声明编写一个函数[(Int, Bool)] -> [[Int]]。我希望该功能仅添加Ints 到同一个嵌套子列表,如果布尔值是True。但是如果布尔值是False, 我想要Int与下一个相关联True要添加到 a 的布尔值new子列表。例如:输入

[(1,True),(2,True),(3,False),(4,True),(5,False),(6,False),(7,True)]

应该返回

[[1,2],[4],[7]]. 

到目前为止我的代码:

test:: [(Int, Bool)] -> [[Int]]
test xs = case xs of
    []->[]
    x:xs
        | snd x == True -> [(fst x)] : test xs
        | snd x == False -> test xs

我目前在将并发整数添加到同一列表时遇到问题(如果它们的布尔值都是)True.


您可以将这个问题分解为两个子问题。

  1. 对于任何给定的列表,获取该列表的头部并将其与列表的其余部分进行匹配。匹配过程中有两种可能性:i) 你成功了,即你匹配了,如果是,你收集匹配的值并继续寻找更多值,或者 ii) 你失败了,即你不匹配,如果是,您立即停止并返回迄今为止与未检查列表的其余部分匹配的结果。
   collectF :: (Eq a) => (a -> Bool) -> [a] -> ([a], [a])
   collectF f [] = ([], [])
   collectF f (x : xs) 
    | f x = let (ys, zs) = collectF f xs in (x : ys, zs)
    | otherwise = ([], x : xs)
  1. 现在您已经有了collectF函数,您可以在输入列表上递归地使用它。在每次调用中,您都会获得一个成功的列表,以及其余未检查的列表。再次对列表的其余部分应用collectF,直到耗尽。
groupBy :: (Eq a) => (a -> a -> Bool) -> [a] -> [[a]]
groupBy _ [] = []
groupBy f (x : xs) = 
    let (ys, zs) = collectF (f x) xs in 
    (x : ys) : groupBy f zs

*Main> groupBy (\x y -> snd x == snd y) [(1,True),(2,True),(3,False),(4,True),(5,False),(6,False),(7,True)]
[[(1,True),(2,True)],[(3,False)],[(4,True)],[(5,False),(6,False)],[(7,True)]]

我将让您从列表中删除 True 和 False 值。另外,请查看 Haskell 的 List 库 [1]。希望我已经说得很清楚了,但是如果您还有其他问题,请告诉我。

[1] http://hackage.haskell.org/package/base-4.12.0.0/docs/src/Data.OldList.html#groupBy http://hackage.haskell.org/package/base-4.12.0.0/docs/src/Data.OldList.html#groupBy

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用递归将列表分解为子列表 的相关文章

随机推荐