score:1

i wrote sumup2 to return either[int, (int, int)]: left is the number of visited elements and the right is a pair of the number of visited elements and running sum.

type intor[a] = either[int, a]
val sumup2: ((int, int), int) => intor[(int, int)] = (pair, y) => {
  val (size, x) = pair
  val sum = x + y
  println(s"sum = $sum, y = $y")
  if (sum > 0) (size + 1, sum).asright else size.asleft 
}

we know that foldm stops when sumup2 returns left so sumup2 won't be invoked for all elements:

scala> val r = foldable[stream].foldm(xs.tostream, (0, 0))(sumup2)
sum = 1, y = 1
sum = 3, y = 2
sum = 6, y = 3
sum = 4, y = -2
sum = -1, y = -5
r: intor[(int, int)] = left(4)

given r: either[int, (int, int)] we can get the tail:

scala> r match { case right(_) => nil; case left(n) => xs.drop(n) }
res63: list[int] = list(-5, 1, 2, 3)

the solution seems to work fine but doesn't look nice to me. how would you improve it ?

score:3

what you can do is accumulate two values (in a tuple): the running sum up until it turns negative or zero; and the tail, which starts to accumulate values then.

val sumup2: ((int, list[int]), int) => id[(int, list[int])] = (x, y) => {
  val sum = if (x._1 < 0) x._1 else x._1 + y
  if (sum > 0) (sum, x._2) else (-1, x._2 ++ list(y))
}

then, you can get the tail from the second element in the tuple:

val xs  = list(1, 2, 3, -2, -5, 1, 2, 3)
val res = foldable[stream].foldm(xs.tostream, (0, list[int]()))(sumup2)

println(res._2)

fiddle here.


Related Query

More Query from same tag