Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scala: adding a method to List?

Tags:

scala

I was wondering how to go about adding a 'partitionCount' method to Lists, e.g.: (not tested, shamelessly based on List.scala):

Do I have to create my own sub-class and an implicit type converter?

(My original attempt had a lot of problems, so here is one based on @Easy's answer):

class MyRichList[A](targetList: List[A]) {
  def partitionCount(p: A => Boolean): (Int, Int) = {
    var btrue = 0
    var bfalse = 0
    var these = targetList
    while (!these.isEmpty) {
      if (p(these.head)) { btrue += 1 }  else { bfalse += 1 }
      these = these.tail
    }
    (btrue, bfalse)
  }
}

and here is a little more general version that's good for Seq[...]:

implicit def seqToRichSeq[T](s: Seq[T]) = new MyRichSeq(s)

class MyRichList[A](targetList: List[A]) {
  def partitionCount(p: A => Boolean): (Int, Int) = {
    var btrue = 0
    var bfalse = 0
    var these = targetList
    while (!these.isEmpty) {
      if (p(these.head)) { btrue += 1 }  else { bfalse += 1 }
      these = these.tail
    }
    (btrue, bfalse)
  }
}
like image 230
ErikR Avatar asked Aug 07 '11 20:08

ErikR


3 Answers

You can use implicit conversion like this:

implicit def listToMyRichList[T](l: List[T]) = new MyRichList(l)

class MyRichList[T](targetList: List[T]) {
    def partitionCount(p: T => Boolean): (Int, Int) = ...
}

and instead of this you need to use targetList. You don't need to extend List. In this example I create simple wrapper MyRichList that would be used implicitly.

You can generalize wrapper further, by defining it for Traversable, so that it will work for may other collection types and not only for Lists:

implicit def listToMyRichTraversable[T](l: Traversable[T]) = new MyRichTraversable(l)

class MyRichTraversable[T](target: Traversable[T]) {
    def partitionCount(p: T => Boolean): (Int, Int) = ...
}

Also note, that implicit conversion would be used only if it's in scope. This means, that you need to import it (unless you are using it in the same scope where you have defined it).

like image 144
tenshi Avatar answered Sep 30 '22 21:09

tenshi


As already pointed out by Easy Angel, use implicit conversion:

implicit def listTorichList[A](input: List[A]) = new RichList(input)

class RichList[A](val source: List[A]) {

    def partitionCount(p: A => Boolean): (Int, Int) = {
        val partitions = source partition(p)
        (partitions._1.size, partitions._2.size)
    }
}

Also note that you can easily define partitionCount in terms of partinion. Then you can simply use:

val list = List(1, 2, 3, 5, 7, 11)
val (odd, even) = list partitionCount {_ % 2 != 0}

If you are curious how it works, just remove implicit keyword and call the list2richList conversion explicitly (this is what the compiler does transparently for you when implicit is used).

val (odd, even) = list2richList(list) partitionCount {_ % 2 != 0}
like image 32
Tomasz Nurkiewicz Avatar answered Sep 30 '22 21:09

Tomasz Nurkiewicz


Easy Angel is right, but the method seems pretty useless. You have already count in order to get the number of "positives", and of course the number of "negatives" is size minus count.

However, to contribute something positive, here a more functional version of your original method:

def partitionCount[A](iter: Traversable[A], p: A => Boolean): (Int, Int) =
   iter.foldLeft ((0,0)) { ((x,y), a) => if (p(a)) (x + 1,y) else (x, y + 1)}
like image 31
Landei Avatar answered Sep 30 '22 19:09

Landei