Handling empty data case for map function

93 views
Skip to first unread message

C.D.

unread,
Jul 30, 2013, 12:00:54 PM7/30/13
to scala...@googlegroups.com
Hi,

In .map calls for Option and List based structures, I would like to handle the case where the variable does not have any data, i.e. I need something like:

val x: Option[Int] = None

val y = x.map { 
  data => {
    data + 10
  }
}.IF_NO_DATA_IN_X {
  45
}

At this point, "y" should have 45. 

Likewise, if x is of type: List[Int]

val y = x.map {
  data => {
    data + 10
  }
}.IF_X_IS_EMPTY {
  List(23)
}


Is there any way of accomplishing this? One alternatife is to use pattern matching (match .. case), but it does not solve every case, and makes it complicated, i.e.

x.matcher {
  Nil => {
    List(23)
  }
  _ => {
    _.map { data => data + 10 }
  }
}

Is there a simpler way of doing it with something like IF_X_IS_EMPTY or IF_NO_DATA_IN_X?

Thanks a lot.
      

Erik Osheim

unread,
Jul 30, 2013, 12:06:24 PM7/30/13
to C.D., scala...@googlegroups.com
On Tue, Jul 30, 2013 at 09:00:54AM -0700, C.D. wrote:
> val x: Option[Int] = None
>
> val y = x.map {
> data => {
> data + 10
> }
> }.IF_NO_DATA_IN_X {
> 45
> }

You want Option's getOrElse method in this case:

x.map(_ + 10).getOrElse(45)

> Likewise, if x is of type: List[Int]
>
> val y = x.map {
> data => {
> data + 10
> }
> }.IF_X_IS_EMPTY {
> List(23)
> }

List doesn't have something built-in that does this. You could add it
if you wanted:

implicit class RicherList[A](as: List[A]) {
def ifEmpty(other: List[A]): List[A] = if (as.isEmpty) other else as
}

xs.map(_ + 10).ifEmpty(23 :: Nil)

Hope this helps!

-- Erik

Michael Shields

unread,
Jul 30, 2013, 12:42:41 PM7/30/13
to scala...@googlegroups.com

Hello again.

 

I’m working through working though Horstrmann’s Scala for the Impatient and he gives the problem in chapter 10:

2. Define a class OrderedPoint by mixing scala.math.Ordered[Point] into java.awt.Point. Use lexicographic ordering, i.e. (x,y) < (x’,y’) if x < x’ or x = x’ and y < y’.

 

Following the example in Odersky (p225):

 

class Rational(n: Int, d: Int) extends Ordered[Rational] {

    // ...

    def compare(that: Rational) = (this.numer * that.denom) - (that.numer * this.denom)

}

 

I tried several variations like:

class OrderedPoint(x : Int, y: Int) extends scala.math.Ordered[java.awt.Point] {

   def compare(that: OrderedPoint ) = if(this.x == that.x) this.y-that.y else

                                      this.x-that.x

}

 

But they all give errors. This version has three errors:

 

error: type mismatch;

found   : that.type (with underlying type this.OrderedPoint)

required: ?{def x: ?}

Note that implicit conversions are not applicable because they are ambiguous:

both method any2Ensuring in object Predef of type [A](x: A)Ensuring[A]

and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]

are possible conversion functions from that.type to ?{def x: ?}

   def compare(that: OrderedPoint ) = if(this.x == that.x) this.y-that.y else

                                                   ^

C:\Users\Mike\IdeaProjects\sfti10\sfti10ex2.scala:10: error: value y is not a me

mber of this.OrderedPoint

   def compare(that: OrderedPoint ) = if(this.x == that.x) this.y-that.y else

                                                                       ^

C:\Users\Mike\IdeaProjects\sfti10\sfti10ex2.scala:11: error: type mismatch;

found   : that.type (with underlying type this.OrderedPoint)

required: ?{def x: ?}

Note that implicit conversions are not applicable because they are ambiguous:

both method any2Ensuring in object Predef of type [A](x: A)Ensuring[A]

and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]

are possible conversion functions from that.type to ?{def x: ?}

                                      this.x-that.x

                                             ^

 

I don’t understand the error messages. I have no idea what the first is trying to say.

For the second and third, in the REPL I can do:

 

scala> val p1 = new java.awt.Point(1,1)

p1: java.awt.Point = java.awt.Point[x=1,y=1]

 

scala> p1.x

res0: Int = 1

 

scala> p1.y

res1: Int = 1

 

scala>

 

So I think .x and .y are members of java.awt.Point so I don’t understand why they wouldn’t be members of OrderedPoint.

 

Thanks for the help,

Mike

Oliver Ruebenacker

unread,
Jul 30, 2013, 12:49:10 PM7/30/13
to Michael Shields, scala...@googlegroups.com

     Hello,

  The first error says you are missing a member "x", which is not surprising since you don't define one, and you don't extend Point. I think you need something like

  class OrderedPoint extends Point with Ordered[Point] ...

     Take care
     Oliver

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Head of Systems Biology Task Force at PanGenX (http://www.pangenx.com)
Any sufficiently advanced technology is indistinguishable from magic.

Oliver Ruebenacker

unread,
Jul 30, 2013, 12:52:03 PM7/30/13
to Michael Shields, scala...@googlegroups.com
Oops, sorry, you do define an x. Nevermind.

C.D.

unread,
Jul 30, 2013, 3:35:18 PM7/30/13
to scala...@googlegroups.com, C.D., er...@plastic-idolatry.com
Ah great! This would work for the list.

But, getOrElse does not work for the option case, because "data + 10" is a simple showcase. In many cases, I need to write some code to do some more complicated calculations... But, for those cases, probably <match ... case> is a better fit.

Thanks again,

er...@plastic-idolatry.com

unread,
Jul 30, 2013, 4:34:33 PM7/30/13
to C.D., scala...@googlegroups.com
On Tue, Jul 30, 2013 at 12:35:18PM -0700, C.D. wrote:
> But, getOrElse does not work for the option case, because "data + 10" is a
> simple showcase. In many cases, I need to write some code to do some more
> complicated calculations... But, for those cases, probably <match ... case>
> is a better fit.

It seems like getOrElse should work in those cases too:

val result: Int = reallyComplicatedFunctionTakingInt(x.getOrElse(999))

Sometimes pattern matching can seem clearer, but I don't think it's
ever necessary, since:

o match {
case Some(x) => f(x)
case None => g()
}

is equal to:

o.map(x => f(x)).getOrElse(g())

Take care,

-- Erik

C.D.

unread,
Jul 30, 2013, 4:59:59 PM7/30/13
to scala...@googlegroups.com, C.D., er...@plastic-idolatry.com
Ah sorry, I missed the map in your first post. This would definitely solve the problem.

Thanks a ton!

Hua Jiang

unread,
Jul 30, 2013, 10:34:58 PM7/30/13
to Oliver Ruebenacker, Michael Shields, scala-user
X and y are not properties of OrderedPoint, because they are declared without 'val' or 'var' keyword. In this way, they are just constructor arguments, and only available in the constructor.

Haoyi Li

unread,
Jul 30, 2013, 10:41:45 PM7/30/13
to Hua Jiang, Oliver Ruebenacker, Michael Shields, scala-user
X and y are not properties of OrderedPoint, because they are declared without 'val' or 'var' keyword. In this way, they are just constructor arguments, and only available in the constructor.

This is mostly correct: for normal (non-case) classes, you need to prefix x and y with `val` or `var` if you want to make them public.

It's slightly wrong in that without `val` and `var`, you get private members, which are available throughout the body of the class (including in the bodies of each method) and not just in the constructor.

Naftoli Gugenheim

unread,
Jul 31, 2013, 1:12:50 AM7/31/13
to Haoyi Li, Hua Jiang, Oliver Ruebenacker, Michael Shields, scala-user
If I'm not mistaken, they're only converted to private members if they are referenced other than in the constructor. So they're automatic potential private members.

Michael Shields

unread,
Aug 1, 2013, 2:50:47 PM8/1/13
to Naftoli Gugenheim, Haoyi Li, Hua Jiang, Oliver Ruebenacker, scala-user

Thanks for the answers. I was able to figure this out with the help. It turns out there were two errors that were making me confused. First, the parameter in scala.math.Ordered[] should be the class name, in this case “OrderedPoint”. Once I fixed that, then the fact that x and y were not declared with val prevented the that.x and that.y from working, even though they are used in the compare so I thought they would be private members of the class. The fact that they are not public doesn’t matter. The following class definition works:

 

class OrderedPoint(private val x : Int, private val y: Int) extends scala.math.Ordered[OrderedPoint] {

  def compare(that: OrderedPoint ) = if(this.x == that.x) this.y-that.y else

                                      this.x-that.x

}

 

Obviously, it works without the “private” for x and y as well.

Thanks,

Mike

Reply all
Reply to author
Forward
0 new messages