blue-sky
blue-sky

Reputation: 53786

How to sum the corresponding values in the List into a Tuple?

I have a list details of this type :

case class Detail(point: List[Double], cluster: Int)

val details = List(Detail(List(2.0, 10.0),1), Detail(List(2.0, 5.0),3),
                   Detail(List(8.0,  4.0),2), Detail(List(5.0, 8.0),2))

I want filter this list into a tuple which contains a sum of each corresponding point where the cluster is 2

So I filter this List :

details.filter(detail => detail.cluster == 2)

which returns :

List(Detail(List(8.0, 4.0),2), Detail(List(5.0, 8.0),2))

It's the summing of the corresponding values I'm having trouble with. In this example the tuple should contain (8+5, 4+8) = (13, 12)

I'm thinking to flatten the List and then sum each corresponding value but

List(details).flatten 

just returns the same List

How to sum the corresponding values in the List into a Tuple ?

I could achieve this easily using a for loop and just extract the details I need into a counter but what is the functional solution ?

Upvotes: 0

Views: 233

Answers (2)

Bask.ws
Bask.ws

Reputation: 843

You can use just one foldLeft with PF without filter:

  details.foldLeft((0.0,0.0))({
    case ((accX, accY), Detail(x :: y :: Nil, 2)) => (accX + x, accY + y)
    case (acc, _) => acc
  })

  res1: (Double, Double) = (13.0,12.0)

Upvotes: 0

Alexey Romanov
Alexey Romanov

Reputation: 170713

What do you want to happen if the lists for different Details have different lengths? Or same length which is different from 2? Tuples are generally only used when you need a fixed in advance number of elements; you won't even be able to write a return type if you need tuples of different lengths.

Assuming that all of them are lists of the same length and you get a list in return, something like this should work (untested):

details.filter(_.cluster == 2).map(_.point).transpose.map(_.sum)

I.e. first get all points as a list of lists, transpose it so you get a list for each "coordinate", and sum each of these lists.

If you do know that each point has two coordinates, this should likely be reflected in your Point type, by using (Double, Double) instead of List[Double] and you can just fold over the list of points, which should be a bit more efficient. Look at definition of foldLeft and the standard implementation of sum in terms of foldLeft:

def sum(list: List[Int]): Int = list.foldLeft(0)((acc, x) => acc + x)

and it should be easy to do what you want.

Upvotes: 5

Related Questions