Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
228 views
in Technique[技术] by (71.8m points)

haskell - Calculating from multiple tuples

I'm trying to take a list of lists of tuple and turn each list of tuples into a single tuple. Like this:

Currently have:

[[("Erikson,Ann",2.0,3),("Erikson,Ann",3.33,3)],[("Lewis,Buck",2.66,1), 
  ("Lewis,Buck",2.0,3)],[("Smith,John",0.0,1),("Smith,John",1.66,3), 
  ("Smith,John",1.33,3)],[("Torvell,Sarah",4.0,3)]]

And I want the form to be a single list of tuples. One tuple for each persons name. Along with combining the list of tuples into a single tuple I want to use the second and third elements of each tuple to calculate the gpa of the person. The second number is the grade point for that class and the third number is the credits for the class. What I need to do is take the sum of credits * gradepoint for each tuple and then divide that sum by the sum of all the credits in each tuple.

What i have so far, that doesn't work is this...

     calcGPA :: MyType2 -> MyType2 -> (String, Double, Double)
     calcGPA (a,b,c) (d,e,f) = (a, ((b*(fromIntegral c))+(e*(fromIntegral 
     f))/(b+e)), 
     (b+e))

Where i am passing in the first list of lists I show at the top of this post.

Am I going in the right direction to solve this problem. Any tips or help would be appreciated.

Thank you


EDIT

Thank you for the help! Helped me understand what was actually going on. I wrote the cumulativeSums fuction as follow:

     cumulativeSums :: (Double, Int) -> (String, Double, Int) -> (Double, 
     Int)
     cumulativeSums (a,b) (c,d,e) = (a+(d*e), b+e)

I'm confused on the chunk of code you have above with the let. Where does this go? Do I put it in its own function that I call passing in the list of list of tuples?

Thank you

________________________________________________________________________________Now that im trying to output credits also

    calcGPA :: [(String, Double, Int)] -> (String, Double, Int)
    calcGPA grades = let name                        = ( (name, _, _) -> 
    name) (head grades)
                         (name, weightedSum, sumOfWeights) = foldl 
    cumulativeSums (name, 0, 0) grades
                 gpa                         = weightedSum / sumOfWeights
                     in  (name, gpa, credits)
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You're going in the right direction if you were planning on using foldl or foldr with your calcGPA function.

What we do when folding is we have a function with the result-so-far, the next element in a list, and the result-just-after. With foldl, which is most appropriate for sums, the type and arguments, as far as lists are concerned is:

foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f startingResult items = …

We see that your function will need to be type (b -> a -> b). Looking elsewhere in the type signature, the ultimate result of foldl is type b. The type of elements in the list is type a.

So what the function you provide foldl does is takes two arguments: the result-so-far and the next item in the list. It then expects your function to give back the result-just-after.

You "fold" in a new item to the result each time your function is run on the next element in the list. So let's look at what our list element type is and what our result type will be.

Our list element type is something like (String, Double, Int). Our result type is (Double, Int). So the type signature for our folding function is:

cumulativeSums :: (Double, Int) -> (String, Double, Int) -> (Double, Int)

So far so good. Now what about the other arguments to foldl? We know the items argument: it's our sublist for one person's grades. We know f, it's our cumulativeSums function we're going to write. What is startingResult? Well, both sums should start with 0, so it's (0, 0). We have:

let name                        = ( (name, _, _) -> name) (head grades)
    (weightedSum, sumOfWeights) = foldl cumulativeSums (0, 0) grades
    gpa                         = weightedSum / sumOfWeights
in  (name, gpa)

Now we write cumulativeSums. Remember, we're getting told the result-so-far and the item from the list. We just need to give back the result-just-after. See if you can write that part.

For the code already provided, I'd recommend writing your own version of it. There are some type errors related to mixing Ints and Doubles in the code above.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...