user1311286
user1311286

Reputation:

Haskell building a list of tuples

I am trying to build a list of tuples. Input is a list of tuples [([char], int1, int2), ...] and the output is the list of tuples such that [([char], int1, int2, (int1/int2)), ...]. I know that this code below is wrong because I think it is building a list of lists of tuples [[(),(),(),()], [(),(),(),()]].

Code:

{- take a list of labels, values, and weights and return list of labels and fractions -}
fraclist [] = []
fraclist x = [ (y,r,q,z) : y <- first (head x) | r <- scnd (head x) | q <- last (head x) | z <- r/q ] : fraclist tail x

{- helper func to get values from tuples -}
frst (a,b,c) = a
scnd (a,b,c) = b
last (a,b,c) = c

How might I get the proper output form as described? Also, how might I output the list of tuples ordered such that the z's are in descending order?

Upvotes: 0

Views: 3420

Answers (3)

DkM
DkM

Reputation: 800

Here is a simple solution without list comprehension:

import Data.List

-- (string, int1, int2) -> (string int1, int2, (int1/int2))
fraclist list = map generateTuple list
    where generateTuple (label, value, weight) = (label, value, weight, (value)/(weight)) 

sortFracListByValueWeightRatio list = sortBy sorter list
    where sorter (_,_,_,d) (_,_,_,h) = if d > h then GT else LT

testList = [("first",3.0,4.0), ("second",4.0,7.0)]

Nothing fancy (I've only used haskell a week).

fraclist works by mapping the generateTuple function to the list. The generateTuple function simply returns a tuple of form (title, value, weight, value/weight). Map is a built in function which simply applies a given function to each element of the list.

The sortFracListByValueWeightRatio (sorry for the long name) uses the built in sortBy function (comes from Data.List), which sorts a given list using a custom function for comparing items. Sorter is my item comparer, and it simply compares the value/weight ratios and returns either GT or LT (Greater Than / Lower Than). Hence, the list items are compared using the custom comparer, and sorted based on its answer.

A significant improvement of readability would probably be to use types to describe the values instead of just tuples. Also I'm using doubles in the test list, but that is easy to change.

Upvotes: 0

Daniel Fischer
Daniel Fischer

Reputation: 183978

I think you want just

fraclist xs = [(y,r,q, r `quot` q) | (y,r,q) <- xs]

(Note: I used quot instead of (/) since you named the components int1, int2.)

A variant not using list comprehensions is

fraclist = map (\(y,r,q) -> (y,r,q, r `quot` q))

Your code doesn't compile, in such cases it is better to post the error message so people can see at one glance what the probable cause is.

You get a parse erro on the first <- in

fraclist x = [ (y,r,q,z) : y <- first (head x) | r <- scnd (head x) | q <- last (head x) | z <- r/q ] : fraclist tail x

because the expression (y,r,q,z) : y <- first (head x) before the first | separating the generated expressions from the generator expressions isn't well-formed. I think it's just a typo and you meant to use | instead of (:) there too.

Then you have several | separators in your list comprehension, which is not valid without the ParallelListComp extension. However, the code doesn't look like a parallel list comprehension is really what you attempt here, since all three values are drawn from the same list. Finally, the last part | z <- r/q is again not well-formed, since r/q is not a list from which elements can be drawn in a list comprehension. You probably intended let z = r/q there.

Upvotes: 1

Matt Fenwick
Matt Fenwick

Reputation: 49115

This code doesn't compile (syntax errors), but after fixing that (I'd recommend reading up on the syntax of list comprehensions (','s vs. '|'s)) and making some other changes:

  • used a list comprehension, which takes care of the base case and the mapping over the list -- so I was able to eliminate fraclist [] = [] and the head/tail/: business

  • used pattern matching to pull the values out of the input tuples -- this is often much easier to read than using functions to take apart values

  • added an explicit type signature for documentation purposes

here's what I think you meant:

fraclist :: (Integral t1) => [(t, t1, t1)] -> [(t, t1, t1, t1)]
fraclist xs = [(x, y, z, div y z) | (x, y, z) <- xs]

I'll leave the sorting to you.

Upvotes: 1

Related Questions