zbstof
zbstof

Reputation: 1072

Sum of even-numbered items in Seq

I'm trying to sum up even numbered items, and I went for making tuples and summing the first values in them, but It's creating a lot of objects which are immediately discarded.

Maybe someone can suggest more lightweight solution (maybe with fold)?

Edit: I meant numbers on even-numbered positions

Testcase:

List(1,3,1,3).foldLeft(x)(magic) === 2

Upvotes: 0

Views: 2926

Answers (10)

Sujit Kamthe
Sujit Kamthe

Reputation: 961

List(1,3,1,3).foldLeft(0)((a, b)=> if(Math.abs(b%2) == 1)a+b else a)

Upvotes: 0

Puneeth Reddy V
Puneeth Reddy V

Reputation: 1568

In addition to above solutions you can use

List(1,2,3,4,5).zipWithIndex.filter(_._2 % 2 == 0).foldLeft(0)( (sum,ele) => {sum+ele._1} );

res6: Int = 9

Upvotes: 0

vsftam
vsftam

Reputation: 145

The List.sliding function is pretty handy here:

List(1,2,3,4).drop(1).sliding(1,2).flatten.sum

Upvotes: 2

Buck
Buck

Reputation: 501

To sum the even-numbered elements of a list without creating an intermediate list first (for performance and memory efficiency), you can do this:

val x = List(1, 11, 2, 22, 3, 33)
val result = x.foldLeft((0,0))((p,e) => if ((p._1)%2==0) (p._1+1, p._2) else (p._1+1, p._2+e))._2
//> result : Int = 66

"p" is a Tuple2[Int, Int] where the first element is the position index and the second element is the cumulative sum. if the position index is even, it returns a new tuple with the next index and accumulating "e". If the position index is odd, it returns a new tuple with the next index but without accumulating "e".

To sum the odd-numbered elements of the list, do the following:

val x = List(1, 11, 2, 22, 3, 33)
val result = x.foldLeft((0,0))((p,e) => if ((p._1)%2==0) (p._1+1, p._2+e) else (p._1+1, p._2))._2
//> result : Int = 6

Upvotes: 0

AmigoNico
AmigoNico

Reputation: 6862

Hmmm. It sounds like performance is a concern here, so I'd skip the zips and folds and go with a tail-recursive solution:

def f( nums:List[Int] ) = {
  def loop( nums:List[Int], soFar:Int ):Int = nums match {
    case x::_::rest => loop( rest, soFar+x )
    case    x::rest => soFar + x
    case          _ => soFar
  }
  loop(nums,0)
}

Upvotes: 1

drexin
drexin

Reputation: 24403

List(1,3,1,3).zipWithIndex.foldLeft(0) { (res, t) =>
  if (t._2%2 == 0)
    t._1 + res
  else
    res
}

zipWithIndex creates for each element in the list a tuple of the element and its index in the list and then you just have to fold and depending on the index either return the result or the result + the current item.

Upvotes: 2

Ben James
Ben James

Reputation: 125217

The other solutions have explicitly used the indices of the elements.

Another way to do it, would be to group into sub-lists of length 2, and take the first element of each:

scala> List(1, 3, 1, 3).grouped(2).map(_.head).sum
res0: Int = 2

(head should be safe to use, because grouped should not return empty lists.)

Upvotes: 3

Brian
Brian

Reputation: 20285

zipWithIndex can be used to zip List(1,3,1,3) with an index and return a List of tuples that can be filtered for even indices, mapped to get the the value, and then summed.

scala> List(1,3,1,3).zipWithIndex 
res0: List[(Int, Int)] = List((1,0),(3,1), (1,2), (3,3))

List(1,3,1,3).zipWithIndex.filter(_._2 % 2 == 0).map(_._1).sum
res1: Int = 2

Upvotes: 4

warpedjavaguy
warpedjavaguy

Reputation: 111

val ls = List(1, 2, 3, 4, 5)
ls.filter(_ % 2 == 0).sum

Edit: position based:

ls.indices.filter(_ % 2 == 0).map(ls(_)).sum

Upvotes: 4

Jatin
Jatin

Reputation: 31744

val ls = List(1,2,3,4,5)
ls.foldLeft(0)((sum,elem) => if(elem%2==0) sum+elem else sum)

There are multiple ways of doing it say by using collect or map, but they all will construct an internal list. For ex:

ls.collect{
  case n:Int if(n%2==0) => n
  case n:Int => 0
}.sum

foldLeft should be the fastest.

Upvotes: 1

Related Questions