Dmitry
Dmitry

Reputation: 13

How to reduce positive elements in collection in scala?

Given an integer array nums:

-2,1,-3,4,6,-1,2,1,1,-5,4

I want to transform this array to another array:

-2,1,-3,10,-1,4,-5,4

Can I add a condition to the reduce function?

Something like that:

...
val nums = Array(-2,1,-3,4,6,-1,2,1,1,-5,4)
val reduced = nums.reduce((x, y) => {
    if (x > 0 && y > 0){
        x + y
    }
})

...

Upvotes: 1

Views: 74

Answers (4)

Feyyaz
Feyyaz

Reputation: 3206

A simple, non-tail recursive one:

def reducePositives(l: List[Int]): List[Int] = {
  l.span(_ > 0) match {
    case (Nil, Nil) => Nil
    case (Nil, np :: rest) => np :: reducePositives(rest)
    case (p, rest) => p.sum :: reducePositives(rest)
  }
}

Upvotes: 0

esse
esse

Reputation: 1551

scala> val nums = Array(-2,1,-3,4,6,-1,2,1,1,-5,4)
nums: Array[Int] = Array(-2, 1, -3, 4, 6, -1, 2, 1, 1, -5, 4)

scala> nums.foldLeft(List[Int]()){ 
         case (init :+ last, num) if last > 0 && num > 0 => init :+ (last + num)
         case (res, num) => res :+ num 
       }
res0: List[Int] = List(-2, 1, -3, 10, -1, 4, -5, 4)

Or:

scala> def reduce(nums: Seq[Int]): Seq[Int] = nums match {
     |   case x1+:x2+:xs => if(x1>0 && x2>0) reduce((x1+x2)+:xs) else x1+:reduce(x2+:xs)
     |   case ns => ns
     | }
def reduce(nums: Seq[Int]): Seq[Int]

scala> reduce(nums)
val res1: Seq[Int] = ArraySeq(-2, 1, -3, 10, -1, 4, -5, 4)

Upvotes: 1

Thomas Böhm
Thomas Böhm

Reputation: 1486

I am not sure if you can use reduce or another simple builtin-function to achieve your goal.

However, you can write a simple tail-recursive function that does what you want (it uses a list and pattern matching):

def sumPositives(arr: Array[Integer]): Array[Integer] = {
    @scala.annotation.tailrec
    def rec(list: List[Integer], acc: List[Integer]): List[Integer] = list match{
      case x :: y :: rest if x >= 0 && y >= 0 => rec(x+y :: rest, acc)
      case x :: y :: rest => rec(y :: rest, x :: acc)
      case x :: Nil => (x :: acc).reverse
      case Nil =>acc.reverse
    }

    rec(arr.toList, List()).toArray
  }

Of course this could be simplified by using a list as input instead of an array, but in your question you specifically mentioned an array.

Upvotes: 0

Ivan Kurchenko
Ivan Kurchenko

Reputation: 4063

You can try next:

val result = Array(-2,1,-3,4,6,-1,2,1,1,-5,4).foldLeft(ListBuffer.empty[Int]) {
  case (result, item) if item < 0 => result :+ item
  case (result, item) if item > 0 => result.lastOption.filter(_ > 0).fold(result :+ item) { positiveSum =>
    result.update(result.size -1, positiveSum + item)
    result
  }
}

println(result)

which will produce desired result: (-2, 1, -3, 10, -1, 4, -5, 4) Hope this helps!

Upvotes: 0

Related Questions