Using zipped collections to initialize a case class in scala - scala

I have to generate a collection of object from some collections of primitive types. So I tried the following two methods and both work:
case class Gr (x:Int,y:Int, z:Int)
val x = List(1,2,4,2,5)
val y = Array(1,2,7,4,5)
val z = Seq(1,2,4,8,5)
(x,y,z).zipped.toList.map(a => Gr(a._1,a._2,a._3))
(x,y,z).zipped.map(Gr:(Int,Int,Int) => Gr)
So, which one is better and how does the second one actually work ? And is there a better way ?

The 1st one can be reduced to (x,y,z).zipped.toList.map(Gr.tupled) and 2nd can be reduced to (x,y,z).zipped.map(Gr), which seems to be shorter/clearer to me.
Recall that the argument to map() is, essentially, A => B, so instead of writing ds.map(d => Math.sqrt(d)), which is type Double => Double, we can simply write ds.map(Math.sqrt) because sqrt() is the correct type.
In this case, the Gr constructor is type (A,A,A) => B. The Scala compiler is able to take the output of zipped and match the constructor type, so the constructor can be used as the argument to map().

Related

Scala: flatten mixed set of sets (or lists or arrays)

I have a Set which incorporates a combination of strings, and subSets of strings, like so:
val s = Set(brand1-_test, Set(brand-one, brand_one, brandone), brands-two, brandthree1, Set(brand-three2, brand_three2, brandthree2))
How do I flatten this so that I have one flat set of strings? s.flatten doesn't work with the following error:
error: No implicit view available from Object => scala.collection.GenTraversableOnce[B]
Neither does flatMap. What am I missing here? The Set could just as easily incorporate a subLists or subArrays (they are the result of a previous function), if that makes a difference.
s.flatMap { case x:Iterable[_] => x; case y => Seq(y) }
Try putting it in a REPL:
scala> val s = Set("s1", Set("s2", "s3"))
s: scala.collection.immutable.Set[Object] = Set(s1, Set(s2, s3))
since you are providing two types (Set and String) then scala infers a type which covers both (Object in this case, but probably Any or AnyRef in most cases) which is not a collection and therefore cannot be flattened.

Scala Future[myType] to MyType

I have Future[MyType] and I need to pass the value of MyType to a method which returns Seq[Future[MyType]], so basic signature of problem is:
val a: Seq[Future[MyType]] = ...
getValue(t: MyType): Seq[Future[MyType]] = {...}
I want to pass value of a to getValue. I tried something like:
val b:Seq[Future[MyType]] = a.map{v => getValue(v)}
I want b to be of Seq[Future[MyType]] type
but, it obviously didn't worked as v is of type Future[MyType] and getValue needs only MyType as parameter. What could be a possible solution??
You can do:
val b = a.map(_.map(getValue(_)))
This will give you a Seq[Future[Seq[Future[MyType]]]]. That's pretty ugly. There are three tools that can make that better.
Future.sequence takes a Seq[Future[A]] and gives you a Future[Seq[A]]. The output future will wait for all input futures to complete before giving a result. This might not always be what you want.
fut.flatMap takes a function computing a Future as a result but does not return a nested Future, as would happen with .map.
You can call .flatten on a Seq[Seq[A]] to get a Seq[A]
Putting this all together, you could do something like:
val b: Seq[Future[Seq[MyType]] = a.map(_.flatMap(x => Future.sequence(getValue(x))))
val c: Future[Seq[MyType]] = Future.sequence(b).map(_.flatten)
More generally, when dealing with "container" types, you'll use some combination of map and flatMap to get at the inner types and pass them around. And common containers often have ways to flatten or swap orders, e.g. A[A[X]] => A[X] or A[B[X]] => B[A[X]].

Get anonymous/unnamed tuple-value by indirect index?

Regard this
val oddOrEven = (odd, even)
oddOrEven._1 would give "odd", while oddOrEven._2 would give "even"
We basically get a tuple with "unnamed" members, if you will so.
But let's assume I wanted to get either odd or even, depending on some external data, like so:
val witness: Int = {numberOfPrevious % 2}
now, let's do this:
val one = oddOrEven._witness
This won't compile.
Is there some special syntax involved or is this simply not possible?
I got curious and wondered whether it was the compiler that could not deduce that the only possible values of witness would be 0 and 1 (but I thought that to be silly on my side, yet I had to try) and tried this:
val oddOrEven = (odd, even)
val witness: Int = {numberOfPrevs % 2}
val v = x match {
case 0 => oddOrEven._1
case 1 => oddOrEven._2
}
Yet again val one = oddOrEven._witness would not work
Then I dug deeper and found out that indeed the compiler would not check for exhaustion. Like:
val v = x match {
case 1 => oddOrEven._1
case 2 => oddOrEven._2
}
would still compile, although 2 was not possible and 0 was missing!
So, I know I am mixing things up here. I am aware that there are matches that are not what is called "exhausting" in my mothertongue, so the possible values are not deduced at compile-time, but at runtime (and indeed I would get a
scala.MatchError: 0 (of class java.lang.Integer)
at runtime.
But, what I'm really interested in: Can I get "unnamed" tuples by an "indirect index" like I mean to?
What about keep it simple, like this:
val oddOrEven = (odd, even)
val witness: Int = {numberOfPrevious % 2} // Or any other calculation of index
oddOrEven.productElement(witness)
You loose type safety while productElement returns Any, but when you know the type of members you can cast, like:
oddOrEven.productElement(witness).asInstanceOf[YourType]
I'm making assumption here that your odd and even values are of the same type, e.g:
sealed trait OddOrEven
case object odd extends OddOrEven
case object event extends OddOrEven
Then:
oddOrEven.productElement(witness).asInstanceOf[OddOrEven]
will give you correct type OddOrEven.
Btw. take a peek at ScalaDoc for Tuple2
You should probably not do that. If you need an index, think about a List or a Vector.
But if you really want this and all of your tuple items are of the same type (for example Int) you could do:
(even, odd).productIterator.collect { case x: Int => 2* x }.toList(0)
Well, you can do something like tuple.productIterator.toList(index-1), but if you want a list, it's probably a better idea to just use a list rather than converting a tuple to it.
And no, compiler doesn't try to figure out all possible ways your code can be executed in order to tell what possible values a variable could take.

Converting a Scala Map to a List

I have a map that I need to map to a different type, and the result needs to be a List. I have two ways (seemingly) to accomplish what I want, since calling map on a map seems to always result in a map. Assuming I have some map that looks like:
val input = Map[String, List[Int]]("rk1" -> List(1,2,3), "rk2" -> List(4,5,6))
I can either do:
val output = input.map{ case(k,v) => (k.getBytes, v) } toList
Or:
val output = input.foldRight(List[Pair[Array[Byte], List[Int]]]()){ (el, res) =>
(el._1.getBytes, el._2) :: res
}
In the first example I convert the type, and then call toList. I assume the runtime is something like O(n*2) and the space required is n*2. In the second example, I convert the type and generate the list in one go. I assume the runtime is O(n) and the space required is n.
My question is, are these essentially identical or does the second conversion cut down on memory/time/etc? Additionally, where can I find information on storage and runtime costs of various scala conversions?
Thanks in advance.
My favorite way to do this kind of things is like this:
input.map { case (k,v) => (k.getBytes, v) }(collection.breakOut): List[(Array[Byte], List[Int])]
With this syntax, you are passing to map the builder it needs to reconstruct the resulting collection. (Actually, not a builder, but a builder factory. Read more about Scala's CanBuildFroms if you are interested.) collection.breakOut can exactly be used when you want to change from one collection type to another while doing a map, flatMap, etc. — the only bad part is that you have to use the full type annotation for it to be effective (here, I used a type ascription after the expression). Then, there's no intermediary collection being built, and the list is constructed while mapping.
Mapping over a view in the first example could cut down on the space requirement for a large map:
val output = input.view.map{ case(k,v) => (k.getBytes, v) } toList

Need help figuring out scala compiler errors

I have been working on a project in scala, but I am getting some error messages that I don't quite understand. The classes that I am working with are relatively simple.
For example:
abstract class Shape
case class Point(x: Int, y: Int) extends Shape
case class Polygon(points: Point*) extends Shape
Now suppose that I create a Polygon:
val poly = new Polygon(new Point(2,5), new Point(7,0), new Point(3,1))
Then if I attempt to determine the location and size of the smallest possible rectangle that could contain the polygon, I get various errors that I don't quite understand.
Below are snippets of different attempts and the corresponding error messages that they produce.
val upperLeftX = poly.points.reduceLeft(Math.min(_.x, _.x))
Gives the error:
"missing parameter type for expanded function ((x$1) => x$1.x)"
val upperLeftX =
poly.points.reduceLeft((a: Point, b: Point) => (Math.min(a.x, b.x)))
Gives this error:
"type mismatch;
found : (Point, Point) => Int
required: (Any, Point) => Any"
I am very confused about both of these error messages. If anyone could explain more clearly what I am doing incorrectly, I would really appreciate it. Yes, I see that the second error says that I need type "Any" but I don't understand exactly how to implement a change that would work as I need it. Obviously simply changing "a: Point" to "a: Any" is not a viable solution, so what am I missing?
The type of reduceLeft is reduceLeft[B >: A](op: (B, A) => B): B, A is Point, and you are trying to apply it to (a: Point, b: Point) => (Math.min(a.x, b.x)).
The compiler reasons thus: Math.min(a.x, b.x) returns Int, so Int must be a subtype of B. And B must also be a supertype of Point. Why? B is the type of the accumulator, and its initial value is the first Point in your Polygon. That's the meaning of B >: A.
The only supertype of Int and Point is Any; so B is Any and the type of op should be (Any, Point) => Any, just as the error message says.
This is Scala 2.8.0.RC2
scala> abstract class Shape
defined class Shape
scala> case class Point(x: Int, y: Int) extends Shape
defined class Point
scala> case class Polygon(points: Point*) extends Shape
defined class Polygon
scala> val poly = new Polygon(new Point(2,5), new Point(7,0), new Point(3,1))
poly: Polygon = Polygon(WrappedArray(Point(2,5), Point(7,0), Point(3,1)))
scala> val upperLeftX = poly.points.reduceLeft((a:Point,b:Point) => if (a.x < b.x) a else b)
upperLeftX: Point = Point(2,5)
reduceLeft requires here a function of the type (Point, Point) => Point. (more precisely (B, Point) => B with B with a lower bound to Point. See Scaladoc at the method reduceLeft.
Another alternative is poly.points.foldLeft(Int.MaxValue)((b, a) => Math.min(b, a.x)), which should also work with Scala 2.7.x. The differences compared to the reduceLeft version are
you have a start value (Int.MaxValue in our case, any real data will be smaller or equal to this)
there are no constraints between the type of the elements and the type of the result, like the lower bound constraint for reduceLeft
Nevertheless Eastsun's solution is more elegant.
BTW if you already have case classes you can ommit the new keyword, and can use the automatically generated factory method in the companion object. So the line creating the poly becomes val poly = Polygon(Point(2,5), Point(7,0), Point(3,1)), which is a bit easier to read.
I see everyone seems to have latched onto the second snippet, so I'll answer the first one:
val upperLeftX = poly.points.reduceLeft(Math.min(_.x, _.x))
You intended that to mean this:
val upperLeftX = poly.points.reduceLeft((a, b) => Math.min(a.x, b.x))
However, that's not how underscore works. There are many meanings to underscore, but two of them are relevant here.
First, it may mean a partial function application. For example, Math.min(_, 0) would partially apply the parameters to min, and return a function that apply the remaining ones. In other words, it is equivalent to x => Math.min(x, 0), ignoring the type annotations. At any rate, this meaning only applies if the underscore is all by itself in the place of one (or more) of the parameters.
That, however, is not the case in your example, because you added a .x after the underscore. If the underscore appears in any kind of expression, such as the method call in your example, then that underscore is a placeholder for a parameter in an anonymous function.
In this second meaning it is particularly important to understand the boundaries of the anonymous function. Specifically, the anonymous function will be delimited by the innermost parenthesis or curly brackets that encloses it, or by any comma.
Now, applying that rule to the expression in the first snippet means that snipper is seen by the compiler like this:
val upperLeftX = poly.points.reduceLeft(Math.min(a => a.x, b => b.x))
So, there are two problems here. First, you are passing two functions to min instead of two doubles. Second, because min isn't expecting to receive functions, the compiler can't infer what the type of these functions might be. Since you did not provide any information about the types of a and b above, it complains about that.
If you did provide such types, the error message would be something like this:
<console>:6: error: type mismatch;
found : Int
required: ?{val x: ?}