List of Option to list of String in scala - scala

how can we typecast in scala for type parameters?
def somefunction[A]():List[A] = {
//call a webservice and some operation on response that gives list of A
return list of A
//ex: List(Some(abc2),Some(abc3),Some(232ab))
}
val l1 : List[A] = somefunction;
how can we convert type l1 (List[A]) to List[String] to get output
like List("abc2","abc3","232ab")?

For something that is always going to be a List[Option[String]] try the below
l1.flatten
It's about as simple aThis will strip out the Some wrappers, leaving only the contained Strings. If you end up with None values however, they will be filtered out of the list, so if you still need those you will need a more complicated process. For instance, if you want to have None mapped to empty string ("")
l1.map(_.getOrElse(""))

You can write a function, which takes a List of any type, and via the universal function .toString () return a String:
def somefunction[A] (as: List[A]): List[String] = as.map (_.toString)
scala> somefunction ("foobar".toList)
res113: List[String] = List(f, o, o, b, a, r)
scala> somefunction (List ("foo", "bar"))
res115: List[String] = List(foo, bar)
scala> somefunction (List (3, 4.4, 1))
res116: List[String] = List(3.0, 4.4, 1.0)
Note, that the common supertyp here is double, so 3 is implicitly converted to 3.0 and then returned as String "3.0".
And you can take a List of Option of something and unwrap every element:
def somefunction[A] (as: List[Option[A]]): List[A] = as.flatten
somefunction: [A](as: List[Option[A]])List[A]
scala> somefunction (List (Some (4), None, Some (3)))
res112: List[Int] = List(4, 3)
But a method, which returns a List of A has somehow to detect, what A is.
You can write a function without parameter, which just returns a constant value:
def version () : String = "2.12"
but the return type is predefined and here, the value, too. In the next example, the value isn't, but the return type is:
scala> def somefunction: Int = scala.util.Random.nextInt (42);
somefunction: Int
scala> somefunction
res117: Int = 21
scala> somefunction
res118: Int = 35
In your example, there is an empty parameter list
def somefunction[A]() = {
return list of A
//ex: List(Some(abc2),Some(abc3),Some(232ab))
}
val l1 : List[A] = somefunction;
How does somethfunction know that you want a List of Option of String? Where might the values come from?
The big-A notation says, that we have a generic type. A typical method would look like this:
def somefunction[A] (a: A) : Option[A] = {
if (a == null) None
else Some (a)
}
Or, with more As:
def somefunction[A] (a: A, b: A) : List[A] = {
List (a, b)
}
maybe without referring to A in the return type:
def somefunction[A] (l: List[A]) : Int = {
l.size ()
}
In somefunction (List(1, 2, 3)), A will then refer to Int, in somefunction (List('a', 'b')) Char and so on. But without a parameter list, referring to the type A, there is no sense in using A as type parameter.
How else can a method return a - let's say a List of - A, with different type of A, depending on some condition?
A random return type can't be specified that way:
scala> def somefunction[A] (): List[A] = {
| val ri = r.nextInt (2)
| if (ri == 0) List (1, 2, 3)
| else List ("foo", "bar")
| }
<console>:31: error: type mismatch;
found : Int(1)
required: A
if (ri == 0) List (1, 2, 3)
^
However, A could depend on an outer type:
scala> case class Sample [A] (a: A) {
| def somefunction (): List[A] = {
| List (a, a, a)
| }
| }
defined class Sample
Note that A isn't annotating the method here, only the class, which could be used like this:
scala> val sample1 = Sample (1)
sample1: Sample[Int] = Sample(1)
scala> val sample2 = Sample ("two")
sample2: Sample[String] = Sample(two)
scala> sample1.somefunction
res119: List[Int] = List(1, 1, 1)
scala> sample2.somefunction
res120: List[String] = List(two, two, two)

Related

How to instantiate multipe variables of multiple types from a method which returns a tuple in Scala

I have a method which returns a tuple:
def someMethod(k: someType): (TypeA, TypeB) = ...
I want to call this method and retrieve the objects of TypeA and TypeB. What is the simplest way to do this?
This does not work:
val (a, b): TypeA, TypeB = myObj.someMethod(someInput)
what does?
Yes, you can (why don't you check it yourself?)
scala> def f(): (Int, Int) = (5, 6)
f: ()(Int, Int)
scala> val (a, b) = f()
a: Int = 5
b: Int = 6
Note, however, that you cannot do multiple assignment to existing variables. Google it, the question has been asked many times.
By the way, your specification of Tuple's type is wrong, you have to wrap it in braces if you want to indicate the type explicitly:
scala> val (c, d): Int, String = (3, "hi")
<console>:1: error: pattern definition may not be abstract
val (c, d): Int, String = (3, "hi")
^
scala> val (c, d): (Int, String) = (3, "hi")
c: Int = 3
d: String = hi

Which calls to unapply can be replaced with parentheses?

So I have known that in Scala you can replace calls to Tuple.unapply with parentheses.
For instance
val tuple: Tuple2[Int, Int] = (1, 2)
val (x, _) = tuple
println(x) //prints 1
However, I recently found out that the following code compiles (although crashes when run, but let's ignore that):
val tuple: Product2[Int, Int] = ???
val (x, _) = tuple
println(x)
So it turns out that calls to Product2.unapply() can be replaced with parentheses. Are there any other classes that can do that?
Quoting the Tuple2 Scala documentation :
A tuple of 2 elements; the canonical representation of a scala.Product2.
When you do val (x, _) = tuple, Tuple2.unapply is still called since you try to pattern match for a tuple, with (x, _) being a more ideomatic alternative to Tuple2(x, _).
val tuple = (1, 2)
val product: Product2[Int, Int] = tuple
val (a, b) = product
// a: Int = 1
// b: Int = 2
You could pattern match using Product2.unapply :
val Product2(a, b) = product
// a: Int = 1
// b: Int = 2
Pattern matching a Tuple2 when you have a Product2 is simalar to :
val list = List(1, 2)
val seq: Seq[Int] = list
val List(a, b) = seq
Which also only compiles when seq is a List, if we created seq as a Vector this doesn't compile :
val seq: Seq[Int] = Vector(1, 2)
val List(a, b) = seq
About your question "Are there any other classes that can do that?", the answer is yes. Basically you can use that syntax with every class for which it is defined a companion object with an unapply method. For example, with a case class you get that automatically. E.g.:
scala> case class Foo(a: String, b: Int, c: String)
defined class Foo
scala> val foo = Foo("hello", 42, "world")
foo: Foo = Foo(hello,42,world)
scala> val Foo(a, _, c) = foo
a: String = hello
c: String = world
As you can see you have to specify the type, you cannot just use it this way:
scala> val (a, _, c) = foo
<console>:12: error: constructor cannot be instantiated to expected type;
found : (T1, T2, T3)
required: Foo
val (a, _, c) = foo
^
The error is basically saying that you have a Tuple3 on the lhs and a Foo on the rhs, so the expression doesn't type check. The reason is that (a, b, c) is actually syntactic sugar for Tuple3(a, b, c):
scala> val (a, b, c) = ("hello", 42, "world")
a: String = hello
b: Int = 42
c: String = world
scala> val Tuple3(a, b, c) = ("hello", 42, "world")
a: String = hello
b: Int = 42
c: String = world
As I said at the beginning of the answer you can also implement your own extractors by defining a custom unapply method within the companion object of your class.

What's wrong with this piece of scala code?

I have the following code snippet which can not be compiled:
val cids = List(1, 2, 3, 4)
val b = Map.newBuilder[Int, Int]
for (c <- cids) {
b += (c, c*2)
}
b.result()
Compiler reports that
console>:11: error: type mismatch;
found : Int
required: (Int, Int)
b += (c, c*2)
I have no idea what's the mistake.
This would work:
for (c <- cids) {
b += ((c, c*2))
}
The parenthesis are parsed by compiler as the argument-list parenthesis of the += function, and not as a tuple. Adding nested parenthesis means a tuple is passed as the argument. It is confusing...
You can fix it the following way:
b += (c->c*2)
This is a duplicate question.
Normally, supplying an untupled arg list works as shown, but it doesn't work when the method is overloaded, because it will choose the method you didn't intend, and not bother to try auto-tupling your args.
scala> class C[A] { def f(a: A) = 42 }
defined class C
scala> val c = new C[(String, Int)]
c: C[(String, Int)] = C#3a022576
scala> c.f("1", 1)
res0: Int = 42
scala> class C[A] { def f(a: A) = 42 ; def f(a: A, b: A, rest: A*) = 17 }
defined class C
scala> val c = new C[(String, Int)]
c: C[(String, Int)] = C#f9cab00
scala> c.f("1", 1)
<console>:14: error: type mismatch;
found : String("1")
required: (String, Int)
c.f("1", 1)
^
An approach using (immutable) values,
(cids zip cids.map(_ * 2)).toMap
Using zip we pair each value with its double, and the resulting list is converted to a Map.
If you go to the documentation you will find : this
The supported API is ms += (k -> v) . That is you need to use
for (c <- cids) {
b += (c -> c*2)
}
Alternately you could use the ((c, c*2)) syntax as suggested above. This is happening because the compiler has no way of knowing that the parentheses are for the tuple. It simply understands that argument as two parameters being passed to the += method.

In Scala 2.10 how to add each element in two generic lists together

I am trying to rewrite some java math classes into Scala, but am having an odd problem.
class Polynomials[#specialized T](val coefficients:List[T]) {
def +(operand:Polynomials[T]):Polynomials[T] = {
return new Polynomials[T](coefficients =
(operand.coefficients, this.coefficients).zipped.map(_ + _))
}
}
My problem may be similar to this question: How do I make a class generic for all Numeric Types?, but when I remove the #specialized I get the same error.
type mismatch; found : T required: String
The second underscore in the map function is highlighted for the error, but I don't think that is the problem.
What I want to do is have:
Polynomial(1, 2, 3) + Polynomial(2, 3, 4) return Polynomial(3, 5, 7)
And Polynomial(1, 2, 3, 5) + Polynomial(2, 3, 4) return Polynomial(3, 5, 7, 5)
For the second one I may have to pad the shorter list with zero elements in order to get this to work, but that is my goal on this function.
So, how can I get this function to compile, so I can test it?
List is not specialized, so there's not much point making the class specialized. Only Array is specialized.
class Poly[T](val coef: List[T]) {
def +(op: Poly[T])(implicit adder: (T,T) => T) =
new Poly(Poly.combine(coef, op.coef, adder))
}
object Poly {
def combine[A](a: List[A], b: List[A], f: (A,A) => A, part: List[A] = Nil): List[A] = {
a match {
case Nil => if (b.isEmpty) part.reverse else combine(b,a,f,part)
case x :: xs => b match {
case Nil => part.reverse ::: a
case y :: ys => combine(xs, ys, f, f(x,y) :: part)
}
}
}
}
Now we can
implicit val stringAdd = (s: String, t: String) => (s+t)
scala> val p = new Poly(List("red","blue"))
p: Poly[String] = Poly#555214b9
scala> val q = new Poly(List("fish","cat","dog"))
q: Poly[String] = Poly#20f5498f
scala> val r = p+q; r.coef
r: Poly[String] = Poly#180f471e
res0: List[String] = List(redfish, bluecat, dog)
You could also ask the class provide the adder rather than the + method, or you could subclass Function2 so that you don't pollute things with implicit addition functions.

General 'map' function for Scala tuples?

I would like to map the elements of a Scala tuple (or triple, ...) using a single function returning type R. The result should be a tuple (or triple, ...) with elements of type R.
OK, if the elements of the tuple are from the same type, the mapping is not a problem:
scala> implicit def t2mapper[A](t: (A,A)) = new { def map[R](f: A => R) = (f(t._1),f(t._2)) }
t2mapper: [A](t: (A, A))java.lang.Object{def map[R](f: (A) => R): (R, R)}
scala> (1,2) map (_ + 1)
res0: (Int, Int) = (2,3)
But is it also possible to make this solution generic, i.e. to map tuples that contain elements of different types in the same manner?
Example:
class Super(i: Int)
object Sub1 extends Super(1)
object Sub2 extends Super(2)
(Sub1, Sub2) map (_.i)
should return
(1,2): (Int, Int)
But I could not find a solution so that the mapping function determines the super type of Sub1 and Sub2. I tried to use type boundaries, but my idea failed:
scala> implicit def t2mapper[A,B](t: (A,B)) = new { def map[X >: A, X >: B, R](f: X => R) = (f(t._1),f(t._2)) }
<console>:8: error: X is already defined as type X
implicit def t2mapper[A,B](t: (A,B)) = new { def map[X >: A, X >: B, R](f: X => R) = (f(t._1),f(t._2)) }
^
<console>:8: error: type mismatch;
found : A
required: X
Note: implicit method t2mapper is not applicable here because it comes after the application point and it lacks an explicit result type
implicit def t2mapper[A,B](t: (A,B)) = new { def map[X >: A, X >: B, R](f: X => R) = (f(t._1),f(t._2)) }
Here X >: B seems to override X >: A. Does Scala not support type boundaries regarding multiple types? If yes, why not?
I think this is what you're looking for:
implicit def t2mapper[X, A <: X, B <: X](t: (A,B)) = new {
def map[R](f: X => R) = (f(t._1), f(t._2))
}
scala> (Sub1, Sub2) map (_.i)
res6: (Int, Int) = (1,2)
A more "functional" way to do this would be with 2 separate functions:
implicit def t2mapper[A, B](t: (A, B)) = new {
def map[R](f: A => R, g: B => R) = (f(t._1), g(t._2))
}
scala> (1, "hello") map (_ + 1, _.length)
res1: (Int, Int) = (2,5)
I’m not a scala type genius but maybe this works:
implicit def t2mapper[X, A<:X, B<:X](t: (A,B)) = new { def map[A, B, R](f: X => R) = (f(t._1),f(t._2)) }
The deeper question here is "why are you using a Tuple for this?"
Tuples are hetrogenous by design, and can contain an assortment of very different types. If you want a collection of related things, then you should be using ...drum roll... a collection!
A Set or Sequence will have no impact on performance, and would be a much better fit for this kind of work. After all, that's what they're designed for.
For the case when the two functions to be applied are not the same
scala> Some((1, "hello")).map((((_: Int) + 1 -> (_: String).length)).tupled).get
res112: (Int, Int) = (2,5)
The main reason I have supplied this answer is it works for lists of tuples (just change Some to List and remove the get).
This can easily be achieved using shapeless, although you'll have to define the mapping function first before doing the map:
object fun extends Poly1 {
implicit def value[S <: Super] = at[S](_.i)
}
(Sub1, Sub2) map fun // typed as (Int, Int), and indeed equal to (1, 2)
(I had to add a val in front of i in the definition of Super, this way: class Super(val i: Int), so that it can be accessed outside)

Resources