1

Suppose I have a class Point with two properties x and y and k tuples:

val p1 = (1,2)
val p2 = (3,4)
val p3 = (33,3)
val p4 = (6,67)
.
.
val p4 = (3,8)

I want to write a function which I can call like:

val arrayOfPoints = tupleToArray(p1,p2,..,pk)

And it will return Array of Points with

  • x = first value of the tuple and
  • y = 2nd value of the tuple.

Note: the number of arguments for the function can be any integer >=1.

Brian
  • 20,195
  • 6
  • 34
  • 55
user1735076
  • 3,225
  • 7
  • 19
  • 16

1 Answers1

4
  • If we define Point as a case class, we can turn a (Int, Int) tuple into a Point using Point.tupled.
  • We can accept a variable number of arguments using the variable arguments notation (Int, Int)*.

A function to turn tuples into Points could look like :

case class Point(x: Int, y: Int)

def tupleToPoints(pairs: (Int, Int)*) = 
  pairs.map(Point.tupled).toArray

scala> tupleToPoints(p1, p2, p3, p4)
res2: Array[Point] = Array(Point(1,2), Point(3,4), Point(33,3), Point(6,67))

If you have a group of points, you can do :

val points = List(p1, p2, p3, p4)
tupleToPoints(points: _*)

Some extra explanation about Point.tupled:

When you call Point(1, 1), you actually call Point.apply(1, 1). If we check the type of Point.apply, we can see it takes two Ints and returns a Point.

scala> Point.apply _
res21: (Int, Int) => Point = <function2>

In your case we have a tuple (Int, Int) which we would like to turn into a Point. The first idea could be pattern matching :

(1, 1) match { case (x, y) => Point(x, y) }

def tupleToPoints(pairs: (Int, Int)*) = 
  pairs.map { case (x, y) => Point(x, y) }.toArray
  // nicer than map(p => Point(p._1, p._2))

But what if we want to use the tuple directly to create a Point using Point.apply, so we don't need this step ? We can use tupled :

scala> (Point.apply _).tupled
res22: ((Int, Int)) => Point = <function1>

We now have a function which takes a tuple (Int, Int) (instead of two Ints) and returns a Point. Because Point is a case class, we can also use Point.tupled which is exactly the same function :

scala> Point.tupled
res23: ((Int, Int)) => Point = <function1>

We can pass this function in our map :

def tupleToPoints(pairs: (Int, Int)*) = 
  pairs.map(Point.tupled).toArray
  // analogous to map(p => Point.tupled(p))
Peter Neyens
  • 9,770
  • 27
  • 33
  • What if I define p =(p1, p2, p3, p4) and want to call this as tupleToPoints(p), how should I change the definition of the function? – user1735076 Jul 28 '15 at 18:21
  • Would `p` be a tuple or a sequence (`List`, `Array`, ...) ? – Peter Neyens Jul 28 '15 at 18:30
  • I want to define val p=((1,2),(3,4),(33,3),(6,67)) & call the method as tupleToPoints(p) and it should return the same result. – user1735076 Jul 28 '15 at 18:31
  • That is not as simple as you might expect. Easier would be `val p = List((1,2),(3,4),(33,3),(6,67))` then you could do `tupleToPoints(p: _*)`. – Peter Neyens Jul 28 '15 at 18:35
  • What _ signifies? and what then would be code for tupleToPoints? I mean I want to call something like: pairs.map(p=>Point(p._1,p._2)) but I see _1 and _2 doesn't work. I don't want to call tupled. – user1735076 Jul 28 '15 at 18:50
  • In my previous comment, `tupleToPoints` would be the same, [more info on `_*`](http://stackoverflow.com/questions/6051302/what-does-colon-underscore-star-do-in-scala?lq=1). I don't know why you wouldn't want to use `Point.tupled`, but your `map` function should work too. – Peter Neyens Jul 28 '15 at 18:57
  • I am doing : case class Point(x: Int, y: Int) def tupleToPoints(pairs: _*) = pairs.map(p => Point(p._1,p._2)).toArray val p = List((1,2),(3,4),(33,3),(6,67)) println(tupleToPoints(p)) but getting error: scala:3: error: not found: type _$1 def tupleToPoints(pairs: _*) = ^ one error found – user1735076 Jul 28 '15 at 19:18
  • You should not use a tuple (like `(p1, p2, p3)`) to represent a group of points, use a `List`, `Array`, `Vector`, ... And you cannot use `_*` inside a function definition. – Peter Neyens Jul 28 '15 at 19:22
  • As you said I am using _* where you said, pardon me if I am mistaking . – user1735076 Jul 28 '15 at 19:25
  • You can use `_*` when you call `tupleToPoints`, but not in its definition. – Peter Neyens Jul 28 '15 at 19:28