【问题标题】:Recursion returning a list of list using haskell递归使用haskell返回列表列表
【发布时间】:2020-01-22 00:09:06
【问题描述】:

我对 Haskell 很陌生,我不确定如何解决/解决这个问题:我想要一个具有类型签名的函数:[((Double, Double), Bool)] -> [[(Double, Double)]]。如果Bool == True,该函数应仅将(Double, Double) 添加到列表列表中。如果 bool 为 False,我希望将与下一个 True bool 关联的 (Double, Double) 添加到新列表中。应将连续的 (Double, Double)Bool == True 配对添加到同一列表中。例如,输入:[((1,1),True),((2,2), False),((3,3), False),((4,4),True),((5,5),True)] 应返回 [[(1,1)],[(4,4),(5,5)]]。我做了一些研究,似乎 groupBy 函数可能有助于解决问题,但我不太确定如何正确使用它。由于我是 Haskell 的新手,我更喜欢更简单的解决方案或解释,但任何建议都会有所帮助。

到目前为止,我的代码只是为与 True bool 关联的每个 (Double, Double) 创建了一个新列表。我不太确定如何添加到列表中的现有列表。

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

【问题讨论】:

标签: list haskell recursion


【解决方案1】:

作为一个学习 Haskell 的新手,甚至还不知道 map 是什么,首先通过简单、直接的递归创建一个独立的定义,而不是使用任何库函数。

简单直接递归的定义只是列举我们可能遇到的情况:

consecTrue :: [(t, Bool)] -> [[t]]
  -- empty list:
consecTrue [] = []
  -- list with exactly one entry in it:
consecTrue [(a,True)] = [[a]]
consecTrue [(a,False)] = []
  -- list with two or more entries in it:
consecTrue ((a1,True) : (a2, True) : more2)  =  (a1:r):q  where  
                                                    (r:q) = consecTrue ((a2,t2) : more2)
consecTrue ((a1,True) : (a2,False) : more2)  =  [a1] : consecTrue more2
consecTrue ((a1,False) : more1)              =  consecTrue more1

(Double, Double) 是无关紧要的无关细节。只需t 就足够了,这意味着任何东西都可以去那里。

【讨论】:

    【解决方案2】:

    是的,可以使用 groupBy。您将需要比较函数来提供 groupBy,我们称之为grf。最简单的方法可能是在交互式命令ghci 中逐步测试解决方案。

    $ ghci
    Prelude> 
    Prelude Data.List> import Data.List
    Prelude Data.List> grf ((x1,y1),p1) ((x2,y2),p2) = (p1==p2)
    Prelude Data.List> let lsa = [((1,1),True),((2,2), False),((3,3), False), ((4,4),True),((5,5),True)]
    Prelude Data.List> 
    Prelude Data.List> lsb = groupBy grf lsa
    Prelude Data.List> lsb
    [[((1,1),True)],[((2,2),False),((3,3),False)],[((4,4),True),((5,5),True)]]
    Prelude Data.List> 
    


    这只是一个开始。然后你需要摆脱错误的,然后摆脱布尔值本身。

    Prelude Data.List> 
    Prelude Data.List> lsc = filter (snd . head) lsb
    Prelude Data.List> lsc
    [[((1,1),True)],[((4,4),True),((5,5),True)]]
    Prelude Data.List> 
    Prelude Data.List> lsd = map (map fst) lsc
    Prelude Data.List> lsd
    [[(1,1)],[(4,4),(5,5)]]
    Prelude Data.List> 
    Prelude Data.List> 
    

    把它们放在一起:

    import Data.List
    
    consecTrue :: [((Double, Double),Bool)] -> [[(Double,Double)]]
    consecTrue xs = let grf ((x1,y1),p1) ((x2,y2),p2) = (p1==p2)
                    in  map (map fst) (filter (snd . head) (groupBy grf xs))
    
    main = do
        let lsa = [((1,1),True),((2,2), False),((3,3), False),
                  ((4,4),True),((5,5),True)]
        let res = consecTrue lsa
    
        putStrLn $ "input  = " ++ show lsa
        putStrLn $ "output = " ++ show res
    

    这似乎是你想要的:

    input  = [((1.0,1.0),True),((2.0,2.0),False),((3.0,3.0),False),((4.0,4.0),True),((5.0,5.0),True)]
    output = [[(1.0,1.0)],[(4.0,4.0),(5.0,5.0)]]
    

    【讨论】:

    • 谢谢 - 看起来不错。您很好地解释了每个步骤;非常清晰易懂。
    • “地图”指的是什么?
    • @anon0987654321 好吧,map 用于将给定函数应用于列表的每个元素,并将所有结果作为新列表返回。例如,如果 sq 是 square 函数,则表达式 map sq [1, 3, 5] 的计算结果为列表:[1, 9, 25]。例如定义here
    猜你喜欢
    • 2013-01-17
    • 1970-01-01
    • 2019-07-21
    • 2014-01-18
    • 1970-01-01
    • 1970-01-01
    • 2019-03-19
    • 1970-01-01
    • 2020-02-23
    相关资源
    最近更新 更多