简体   繁体   English

递归使用 haskell 返回列表

[英]Recursion returning a list of list using haskell

I'm quite new to Haskell and i'm not sure how to solve / approach this problem: I want a function with the type signature: [((Double, Double), Bool)] -> [[(Double, Double)]] .我对 Haskell 很陌生,我不知道如何解决/解决这个问题:我想要一个带有类型签名的 function: [((Double, Double), Bool)] -> [[(Double, Double)]] The function should only add (Double, Double) to the list of lists if Bool == True .如果Bool == True ,则 function 应仅将(Double, Double)添加到列表列表中。 If the bool is False, I want the (Double, Double) associated with the next True bool to be added to a new list.如果 bool 为 False,我希望将与下一个 True bool 关联的(Double, Double)添加到新列表中。 Consecutive (Double, Double) 's paired with Bool == True should be added to the same list.Bool == True配对的连续(Double, Double)应该添加到同一个列表中。 For example, an input of: [((1,1),True),((2,2), False),((3,3), False),((4,4),True),((5,5),True)] should return [[(1,1)],[(4,4),(5,5)]] .例如,输入: [((1,1),True),((2,2), False),((3,3), False),((4,4),True),((5,5),True)]应该返回[[(1,1)],[(4,4),(5,5)]] I did a little research and it seems like the groupBy function might be useful in solving the problem, but I'm not quite sure how to use it properly.我做了一些研究,似乎 groupBy function 可能有助于解决问题,但我不太确定如何正确使用它。 As I'm new new to Haskell I'd prefer a more simple solution or explanation but any suggestions would help.由于我是 Haskell 的新手,我更喜欢更简单的解决方案或解释,但任何建议都会有所帮助。

So far my code just creates a new list for every (Double, Double) associated with True bool.到目前为止,我的代码只是为与 True bool 关联的每个(Double, Double)创建了一个新列表。 I'm not quite sure how to add to an existing list within a list.我不太确定如何添加到列表中的现有列表。

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

Yes, groupBy can be used.是的,可以使用 groupBy。 You will need the comparison function to feed groupBy, let's call it grf .您将需要比较 function 来提供 groupBy,我们称之为grf Easiest path is probably to test the solution gradually within the interactive command, ghci .最简单的方法可能是在交互式命令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> 


That's just a start.这只是一个开始。 Then you need to get rid of the false ones, and then to get rid of the boolean values themselves.然后你需要摆脱虚假的,然后摆脱 boolean 值本身。

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> 

Putting it all together:把它们放在一起:

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

That seems to do what you wanted:这似乎做你想要的:

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)]]

As a newcomer learning Haskell, not even yet knowing what map is, it makes total sense to have been asked to do this first of all by simple, direct recursion, creating a definition which stands on its own, not using any library functions.作为一个学习 Haskell 的新手,甚至还不知道map是什么,首先通过简单、直接的递归来创建一个独立的定义,而不使用任何库函数,这是完全有意义的。

And definition by simple direct recursion is just enumeration of possible cases we're presented with:简单直接递归的定义只是列举我们遇到的可能情况:

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

The (Double, Double) is immaterial, extraneous detail. (Double, Double)是无关紧要的、无关紧要的细节。 Just t is enough, meaning anything can go there.只要t就足够了,这意味着任何东西都可以 go 在那里。

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

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