Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use a Scala collection method to help convert a list of [0,0,0,1,1,1,1,0,0,1,1] into [3,4,2,2]

So I have a list of 0's and 1's, I want to find the count of each element and output this to a list. I can think of a recursive way to do it with functions but is there any helper functions which can help to convert this?

I believe groupBy could be useful but it seems to group all the elements into one partition or another, not into the way I want.

I want to have a list of the count of numbers until each transition from 0 to 1 and 1 to 0. ie, if we have 0,0,0, .. ok we counted 3 zeros so remember 3, then we have 1,1,1,1 so we counted 4 1's, so we remember 4, so far we have a list of [3,4...] and so on

like image 317
Phil Avatar asked Nov 29 '13 08:11

Phil


4 Answers

tail-rec version of Yann Moisan's solution:

    def pack[A](ls: Seq[A], prev: Seq[Int] = Seq.empty): Seq[Int] = {
        if (ls.isEmpty) prev
        else {
            val (packed, next) = ls span {_ == ls.head }
            pack(next, prev :+ packed.size)
        }
    }
like image 121
Sergey Passichenko Avatar answered Nov 01 '22 03:11

Sergey Passichenko


def pack[A](ls: List[A]): List[Int] = {
  if (ls.isEmpty) List(0)
  else {
    val (packed, next) = ls span { _ == ls.head }
    if (next == Nil) List(packed.size)
    else packed.size :: pack(next)
  }
}
like image 32
Yann Moisan Avatar answered Nov 01 '22 01:11

Yann Moisan


This might be a little complicated. but I'd go with it.

scala> implicit class ListHelper[A](ls:List[A]) {
         def partitionBy(f: (A, A) => Boolean) = if (ls.isEmpty) List.empty[Int] 
           else (ls zip (ls.head :: ls)).foldLeft(List.empty[Int]){
             case (Nil, _) => List(1)
             case (x :: xs, (a, b)) => if (a == b) (x + 1) :: xs else 1 :: x :: xs
         }.reverse
       }
defined class ListHelper

scala> List(0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1).partitionBy(_ == _)
res27: List[Int] = List(3, 4, 2, 2)

This is based on the clojure function partition-by

like image 1
tiran Avatar answered Nov 01 '22 02:11

tiran


This is groupBy.

 val tuple = list.foldRight((0,0)) { (x, accum) =>
     if (x == 0) (accum._1 +1, accum._2) else (accum._1, accum._2 +1) 
 }
 List(tuple._1, tuple._2)

on similar lines here is fliptracker (for non-empty lists):

def fliptracker(list: List[Int]) = {

    val initial = (list.head, 0, List.empty[Int])

    val result = list.foldLeft(initial) {

        (acc, x) =>

          if (acc._1 == x) (acc._1, acc._2 + 1, acc._3) 
          else (x, 1, acc._3 ::: List(acc._2))
    }

    result._3 ::: List (result._2)
}       

fliptracker(List(0,0,0,1,1,1,1,0,0,1,1)) // List(3, 4, 2, 2)
like image 1
Shyamendra Solanki Avatar answered Nov 01 '22 01:11

Shyamendra Solanki