Brivvirs
Brivvirs

Reputation: 2493

Haskell - if else return clean tuple

My homework task is to group two tuples in a list if the second element of the first tuple is the same as the first element of the second tuple. Then, if the first tuple is (a, b) and the second is (b, c), the tuple (a, c) must be added to the result list.

I wrote first function wich takes element with one tuple and second list with many tuples and compare each to each.

this one works correcly:

c1 = ("a","x")
d1 = [ ("x","b"), ("z","c"), ("x","b"), ("z","c")
     , ("x","b"), ("z","c"), ("x","b"), ("z","c") ]

getByOne c1 a1 = filter (/=[])
  [ if (fst  (last(take n a1))) == (snd c1)
    then [((fst c1),  (snd  (last(take n a1))))]
    else  [] | n <- [1..(length a1) ] ]

output:

[ [("a","b")], [("a","b")], [("a","b")], [("a","b")] ]

But the problems is that I can't throw in if then and else statement just simple tuple, so I create a new list. In the end of this "workaround" i am getting list in list in list and so on. Also if output list was bigger, there were be more lists in lists.

Is there any way to pass out only tuple or empty tuple or i should somehow group theses lists ?

Upvotes: 5

Views: 1136

Answers (2)

m09
m09

Reputation: 7493

  1. [1..(length a1)] can be written [1 .. length a1]
  2. [ if (fst  (last(take n a1))) == (snd c1)
      then [((fst c1),  (snd  (last(take n a1))))]
      else  [] | n <- [1..(length a1) ] ]
    

    can be written

    [ if fst lastElement == snd c1
      then [(fst c1, snd lastElement)]
      else [] | n <- [1 .. length a1 ]
              , let lastElement = last (take n a1) ]
    
  3. Then, instead of using the list index to go through it, use the list directly:

    [ if x == snd c1
      then [(fst c1, y)]
      else [] | (x, y) <- a1 ]
    
  4. Then, instead of using a list to represent the existence or not of a solution, use Maybe:

    import Data.Maybe
    
    c1 = ("a","x")
    d1 = [ ("x","b"), ("z","c"), ("x","b"), ("z","c")
         , ("x","b"), ("z","c"), ("x","b"), ("z","c") ]
    
    getByOne c1 a1 = catMaybes
            [ if x == snd c1
              then Just (fst c1, y)
              else Nothing | (x, y) <- a1 ]
    
  5. Better yet, use a guard and get rid of the if then else:

    getByOne (a, b) a1 = [ (a, d) | (c, d) <- a1
                                  , b == c ]
    

Alternatively, if you want to use filter, you first filter the list of matching tuples, then build the corresponding results with map:

getByOne (a, b) a1 = map (\(_, c) -> (a, c))
                     . filter (\(c, _) -> b == c)
                     $ a1

which simplifies into

getByOne (a, b) = map (\(_, c) -> (a, c))
                     . filter (\(c, _) -> b == c)

Upvotes: 3

Daniel Fischer
Daniel Fischer

Reputation: 183873

You can flatten the result using

concat :: [[a]] -> [a]

then you don't even need to filter (/=[]) - by the way, the condition (/= []) is more idiomatically written not . null, since the null test doesn't impose an Eq constraint on its argument (you already have one here, so it's just a matter of idiom).

Further, last (take n a1) is just the n-th element of a1 if 1 <= n <= length a1. Since you have that restriction imposed, that can more succinctly be expressed as a1 !! (n-1)

Then you have structurally

getByOne c1 a1 = concat $ [something c1 (a1 !! i) | i <- [0 .. length a1 - 1]]

(I have shifted indices to index by i), which is clearer and more efficiently expressed as

getByOne c1 a1 = concat $ map (something c1) a1

If you prefer a list comprehension to map, you can also write that as

getByOne c1 a1 = concat [something c1 x | x <- a1]

which in your case, using the ability to pattern-match in alist-comprehension generator, gives us

getByOne (f,s) a1 = concat [ if a == s then [(f,b)] else [] | (a,b) <- a1]

which is much shorter and more readable. Instead of using if condition then [element] else [] and concat, even nicer is to use a condition in the list comprehension,

getByOne (f,s) list = [(f,b) | (a,b) <- list, a == s]

which is short and clear.

Upvotes: 9

Related Questions