Partial reduce on collection

15 views
Skip to first unread message

Edmondo Porcu

unread,
Jan 12, 2012, 11:33:47 AM1/12/12
to scala-user
Dear all,
given two arrays, one of boolean and one of double with the same size, I need to produce a third array of doubles containing partial sums of the double array. 
I zipped the two arrays, and now I need , when an item has its boolean = false to sum it to the following until one is found with flag =true

Example:

True 0.1
true 0.2
false 0.3
false 0.4
true 0.5

Result =>
0.1
0.2
0.5+0.4+0.3=1.2

Which is the best way to do this in Scala

Best Regards
Edmondo

√iktor Ҡlang

unread,
Jan 12, 2012, 11:41:28 AM1/12/12
to Edmondo Porcu, scala-user

Best in what respect?

 

Best Regards
Edmondo



--
Viktor Klang

Akka Tech Lead
Typesafe - The software stack for applications that scale

Twitter: @viktorklang

Sciss

unread,
Jan 12, 2012, 11:48:43 AM1/12/12
to Edmondo Porcu, scala-user
val x = List(true, true, false, false, true )
val y = List( 0.1, 0.2, 0.3, 0.4, 0.5 )

val filter = x.zip(true :: x.init).map({ case (pred, succ) => !pred || !succ }) // --> false, false, true, true, true
y.zip(filter).collect({ case (x, true) => x }).sum

Edmondo Porcu

unread,
Jan 12, 2012, 11:49:22 AM1/12/12
to scala-user
Something better than this crap

  lazy val groupedItems = {
    val grouped= Array.ofDim(activeCount)[Double];
    var i = 0;
    var k = 0;
    var sum=0d;
    while(i<original.size){
      sum+= original (i);
      if(flags(i)){
        output(k)=sum;
        k+=1;
        sum=0;
      }
    }
    grouped;
  }


2012/1/12 √iktor Ҡlang <viktor...@gmail.com>

Sciss

unread,
Jan 12, 2012, 12:04:28 PM1/12/12
to Sciss, Edmondo Porcu, scala-user
(
actually you can just do

val filter = x.zip(true :: x).map({ case (pred, succ) => !pred || !succ })

because the zipped result will be as short as the shorter of the two inputs, and i guess `init` is an expensive operation for large `List`s.
)

Rex Kerr

unread,
Jan 12, 2012, 12:38:02 PM1/12/12
to Edmondo Porcu, scala-user
Do you want this to be fast to run or fast to code?

Let's say we have
   val ns = Array(0.1, 0.2, 0.3, 0.4, 0.5)
   val tf = Array(true, true, false, false, true)

If you want it to be fast to run, it's a bit of work, as you've already shown:

  def chopsum(ns: Array[Double], tf: Array[Boolean]) = {
    var i = 0
    var n = 0
    val L = math.min(ns.length, tf.length)
    while (i < L) {
      if (tf(i)) n += 1
      i += 1
    }
    if (!tf(L-1)) n += 1
    val result = new Array[Double](n)
  var i = 0
  var n = 0
  while (i < L) {
    result(n) += ns(i)
    if (tf(i)) n += 1
    i += 1
  }
  result

If you want your code to be compact, you can, for instance,

  def chopsum(xs: Seq[(Double, Boolean)], answer: Vector[Double] = Vector()): Vector[Double] = {
    if (xs.isEmpty) answer
    else {
      val (pre, post) = xs.span(! _._2)
      chopsum(post.drop(1), answer :+ (pre ++ post.take(1)).map(_._1).sum)
    }
  }
  chopsum(ns zip ts)

This is about the best you can do, given that Scala doesn't have a chop-into-groups method.  I have one on StackOverflow at http://stackoverflow.com/questions/5410846 as my example of adding a method to collections.  Using that (the version that works with arrays), one could simply

  (ns zip tf).groupedWhile((x,_) => !x._2).map(_.map(_._1).sum)

which illustrates why such a method was sufficiently heavily asked-for that I used it as my example.

  --Rex
Reply all
Reply to author
Forward
0 new messages