简体   繁体   中英

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)]] . The function should only add (Double, Double) to the list of lists if Bool == True . If the bool is False, I want the (Double, Double) associated with the next True bool to be added to a new list. Consecutive (Double, Double) 's paired with Bool == True should be added to the same list. 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)]] . 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. As I'm new new to Haskell I'd prefer a more simple solution or explanation but any suggestions would help.

So far my code just creates a new list for every (Double, Double) associated with True bool. 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. You will need the comparison function to feed groupBy, let's call it grf . Easiest path is probably to test the solution gradually within the interactive command, 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.

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.

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. Just t is enough, meaning anything can go there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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