I need to concatenate strings present inside a WrappedArray in Scala. I am able to do it with the help of List but that is not what I have to do. I want a solution specifically designed for WrappedArray and with scope of adding/deleting elements while concatenating. I have to use this function as a udf for transforming data via Spark SQL collect_list. That is why I am forced to use WrappedArray.
For e.g ->
WrappedArray("I","love","coding")
Output : String = I : love : coding
This is just an example like adding a colon. I am facing various type issues while matching in case of Wrapped Array.
import scala.annotation.tailrec
object tailRecursionString {
def getString(ints :scala.collection.mutable.WrappedArray[String]): String = {
#tailrec
def sumAccumulator(ints: scala.collection.mutable.WrappedArray[String], accum: String): String = {
ints match {
case Nil : => accum
case x :: tail => sumAccumulator(tail, accum + x)
}
}
sumAccumulator(ints, "[") + "]"
}
def main(args: Array[String]): Unit = {
val list : scala.collection.mutable.WrappedArray[String] = Array("kumar","sambhav","is","a","good","boy")
val sum = getString(list)
println(sum)
}
}
The reason of your problems is using WrappedArray which hasn't unapply method. Pattern matching works using unapply method, you can read more about this in scala documentation. Just replace WrappedArray to Array and matching expressions then it should works:
#tailrec
def sumAccumulator(ints: Array[String], accum: String): String = {
ints match {
case Array() => accum
case _ => sumAccumulator(ints.tail, accum + ints.head)
}
}
List has subtypes :: and Nil. They are case classes and case classes have unapply method generated by compiler.
Shortly, I try to describe how it works:
When compiler looking for extracting (in pattern matching) it looks at ::, sees that it's a subtype of List and has unapply method, and if unapply returns correct result it's choose this branch. The same way for Nil.
You could write it for Seq in general :
import scala.annotation.tailrec
def getString(ints :Seq[String]): String = {
#tailrec
def sumAccumulator(ints: Seq[String], accum: String): String = {
ints match {
case Seq(x) => accum
case Seq(x, xs#_*) => sumAccumulator(xs, accum + x)
}
}
sumAccumulator(ints, "[") + "]"
}
As WrappedArray is also a Seq, this will work
val seperator = " "
s"[${scala.collection.mutable.WrappedArray("I", "love", "coding").mkString(seperator)}]"
In case if you want to apply a filter, you can still use filter, and achieve the same.
<script src="https://scastie.scala-lang.org/lttp77S4Sout7VWkOXTEhQ.js"></script>
Related
I have a list and two strings :
val features = List("one","two","three")
val strOne = "one_five"
val strTwo = "seven_five"
I'd like to match each string to items of the list.
If beginning of string matches one of list items then print matched list item and string itself.
If not, nothing to print.
I have method that I think make what I need but I cannot compile it :
def getElement(any: String): String = any match {
case s :: rest if features.contains(s) => s + "= " + any
case _ => // Nothing
}
I wanted the following :
scala> getElement(strOne)
"one_five= one"
scala> getElement(strTwo)
You can't just return nothing. You promised that your method would return a String, so you must return one. You can either return an Option[String] (preferred) or return Unit and do the printing yourself. Further, the built in method TraversableLike#find will do part of the job.
def findFeature(str: String): Option[String] = features.find(_ startsWith str) map { value => s"$str=$value" }
In order to get the printing behavior:
findFeature(str) foreach println
// or redefine findFeature similarly
Further, you seem to misunderstand pattern matching: You don't want to match on the string; you want to match the list's elements against the string. Here's a version that uses pattern matching:
def getElement(feature: String): Option[String] = {
#tailrec def getElem0(feature: String, strs: List[String]): Option[String] = strs match {
case s :: _ if s startsWith feature => Some(s"$feature=$s") // Matching case
case _ :: rest => getElem0(feature, rest) // Not matched, but more to search
case Nil => None // Empty list; failure
}
getElem0(feature, features)
}
Your solution can't compile because :: is a List method, and s is a String. Moreover, getElement is declared to return a String therefore it should return a String for any input. So you can't just return "nothing" in the second case.
Here's an alternative implementation:
def printElement(any: String): Unit = features
.find(s => any.startsWith(s)) // find matching (returns Option[String])
.foreach(s => println(s + "= "+ any)) // print if found
printElement(strOne) // one= one_five
printElement(strTwo)
Simple one line Scala code
Find in list the item who's first part is present in the list
features.find(_ == str.split("_")(0)).map { elem => s"$str= $elem"}.getOrElse("")
Put the above line inside the function.
def getElement(str: String): String = features.find(_ == str.split("_")(0)).map { elem => s"$str= $elem"}.getOrElse("")
Scala REPL
scala> val strOne = "one_five"
strOne: String = one_five
scala> val str = "one_five"
str: String = one_five
scala> features.find(_ == str.split("_")(0)).getOrElse("")
res2: String = one
scala> features.find(_ == str.split("_")(0)).map(elem => s"$str= $elem").getOrElse("")
res3: String = one_five= one
I want to update a sequence in Scala, I have this code :
def update(userId: Long): Either[String, Int] = {
Logins.findByUserId(userId) map {
logins: Login => update(login.id,
Seq(NamedParameter("random_date", "prefix-" + logins.randomDate)))
} match {
case sequence : Seq(Nil, Int) => sequence.foldLeft(Right(_) + Right(_))
case _ => Left("error.logins.update")
}
}
Where findByUserId returns a Seq[Logins] and update returns Either[String, Int] where Int is the number of updated rows,
and String would be the description of the error.
What I want to achieve is to return an String if while updating the list an error happenes or an Int with the total number of updated rows.
The code is not working, I think I should do something different in the match, I don't know how I can check if every element in the Seq of Eithers is a Right value.
If you are open to using Scalaz or Cats you can use traverse. An example using Scalaz :
import scalaz.std.either._
import scalaz.std.list._
import scalaz.syntax.traverse._
val logins = Seq(1, 2, 3)
val updateRight: Int => Either[String, Int] = Right(_)
val updateLeft: Int => Either[String, Int] = _ => Left("kaboom")
logins.toList.traverseU(updateLeft).map(_.sum) // Left(kaboom)
logins.toList.traverseU(updateRight).map(_.sum) // Right(6)
Traversing over the logins gives us a Either[String, List[Int]], if we get the sum of the List we get the wanted Either[String, Int].
We use toList because there is no Traverse instance for Seq.
traverse is a combination of map and sequence.
We use traverseU instead of traverse because it infers some of the types for us (otherwise we should have introduced a type alias or a type lambda).
Because we imported scalaz.std.either._ we can use map directly without using a right projection (.right.map).
You shouldn't really use a fold if you want to exit early. A better solution would be to recursively iterate over the list, updating and counting successes, then return the error when you encounter one.
Here's a little example function that shows the technique. You would probably want to modify this to do the update on each login instead of just counting.
val noErrors = List[Either[String,Int]](Right(10), Right(12))
val hasError = List[Either[String,Int]](Right(10), Left("oops"), Right(12))
def checkList(l: List[Either[String,Int]], goodCount: Int): Either[String, Int] = {
l match {
case Left(err) :: xs =>
Left(err)
case Right(_) :: xs =>
checkList(xs, (goodCount + 1))
case Nil =>
Right(goodCount)
}
}
val r1 = checkList(noErrors, 0)
val r2 = checkList(hasError, 0)
// r1: Either[String,Int] = Right(2)
// r2: Either[String,Int] = Left(oops)
You want to stop as soon as an update fails, don't you?
That means that you want to be doing your matching inside the map, not outside. Try is actually a more suitable construct for this purpose, than Either. Something like this, perhaps:
def update(userId: Long): Either[String, Int] = Try {
Logins.findByUserId(userId) map { login =>
update(login.id, whatever) match {
case Right(x) => x
case Left(s) => throw new Exception(s)
}
}.sum
}
.map { n => Right(n) }
.recover { case ex => Left(ex.getMessage) }
BTW, a not-too-widely-known fact about scala is that putting a return statement inside a lambda, actually returns from the enclosing method. So, another, somewhat shorter way to write this would be like this:
def update(userId: Long): Either[String, Int] =
Logins.findByUserId(userId).foldLeft(Right(0)) { (sum,login) =>
update(login.id, whatever) match {
case Right(x) => Right(sum.right + x)
case error#Left(s) => return error
}
}
Also, why in the world does findUserById return a sequence???
While practicing scala, I am trying to insertion-sort an integer list using pattern matching. Previously, the following code for printing the list worked absolutely fine:
object PrintList {
def iPrint(xs: List[Int]):Unit = xs match {
case x :: ys => {
print(x+" -> ")
iPrint(ys)
}
case _ => println("Nil")
}
def main(args: Array[String]) {
//val l = Nil.::(1).::(2).::(3).::(4)
val l = 4 :: 3 :: 2 :: 1 :: Nil
iPrint(l)
}
}
However, the following code to sort a list doesn't compile:
def insert(x : Int, l1 : List[Int]):List = {
//stubbed
List()
}
def iSort(l : List[Int]):List = l match {
case x :: ys => insert(x , iSort(ys))
case Nil => Nil
}
Am I missing something really trivial here??
EDIT:
Modified the code as below:
def insert(x : Int , l1 : List[Int]):List[Int] = {
//stubbed
List(0)
}
def iSort(l : List[Int]):List[Int] = l match {
case (x:Int) :: (ys:List[Int]) => insert(x , iSort(ys))
case _ => List(0)
}
Still getting error in the first case statement - Pattern type is incompatible with expected type. Found: ::[B], expected: List[Int]
Using Intellij Idea with scala plugin - 2.11.7.
Looking at your screenshot, you are defining your own List class in that same package Week04. It's visible in your project browser on the left-hand side. So in your code
def iSort(l: List[Int]) = ???
you have an argument of type Week04.List[Int]. You try to destructure that using the :: list-cons class. I presume you have not defined your version of ::, least I don't remember that this was defined the Coursera class. So you have a scala.:: here which is a sub-type of scala.List. So you are trying to pattern match against some completely different type. If you replaced every occurance of List with scala.List you would use Scala's standard list class instead and it should work. If you want that to work with your own list implementation, you need to define your own extractor.
I'm wondering what is idiomatic way to applying some operation on the List if it is not empty, and return empty List (Nil) if list is empty.
val result= myList match {
case Nil => Nil // this one looks bad for me
case nonEmpty => myService.getByFilters(nonEmpty)
}
Just using map operation on the list will trigger loop, but I want to achieve same result as map for Option type - i.e. do something only once if List is non-empty, and do nothing if List is empty
I think your design is not quite right perhaps. You should be just able to pass any list into the getByFilters function and it should just handle lists of any length. So there should be no need for these sorts of checks.
If the design change is not possible there is nothing wrong with if:
val result = if(myList.isEmpty) Nil else myService.getByFilters(myList)
It's idiomatic because if returns values. Maybe there are other clean ways, I don't know.
If you just want to require non empty list argument you can use HList or alternatively, you can use this trick:
def takesNonEmptyList[T](head: T, tail: T *): List[T] = head :: tail.toList
You can do something fake to make it seem look idiomatic, but I would not recommend it. It's unclear and unnecessary complication:
def getByFilters(xs: List[Int]) = xs.filter(_ % 2 == 0)
val res = l.headOption.map(_ :: l.tail).map(getByFilters).getOrElse(Nil)
println(res)
prints List(2, 4)
If you really want it, you can just implement your own semantic:
implicit class MySpecialList[T](xs: List[T]) {
def mapIfNotEmpty[R](f: List[T] ⇒ List[R]): List[R] =
if (xs.isEmpty) Nil else f(xs)
}
def getStuff(xs: List[Int]) = xs.map(_ + " OK")
val x: List[Int] = List(1,2,3)
val y: List[Int] = List()
def main(args: Array[String]): Unit = {
val xx = x.mapIfNotEmpty(getStuff) // List("1 OK", "2 OK", "3 OK")
val yy = y.mapIfNotEmpty(getStuff) // List()
}
There is method headOption in List, so you could use option semantic to lift List to Option[List]:
import scala.collection.TraversableLike
implicit class TraversableOption[T <: TraversableLike[_, T]](traversable: T) {
def opt: Option[T] = traversable.headOption.map(_ => traversable)
}
you can use it as:
val result = myList.opt.fold[List[Int]](Nil)(myService.getByFilters)
By invoking each filter service separately,
myList.flatMap(filter => myService.getByFilters(List(filter)))
it gets an empty list if myList is empty. If performance may be a matter, consider also a parallel version with
myList.par
I am hoping to write a Scala method which takes in a tuple of any size and type along with an index, and returns the element in the tuple at that index. I know how to do everything but preserve the type. I haven't yet figured out a way to make the return value be of the dynamic type of the tuple item.
Here is the function I have so far:
def subscript_get(tup: Product, index:Int): Any={
return tup.productElement(index)
}
The usage for example would be:
subscript_get((0,1,2,3),0)
--> Int = 0
subscript_get((0,1,"asdf",3),2)
--> java.lang.String = asdf
I know that I can cast the result back afterwards to what I am looking for, but this doesn't work for me because I can't always know what type I should cast to.
Is something like this even possible ? Thanks!
I'm not sure you want a solution that uses macros, but for the record (and since I've written precisely this method before), here's how you can implement this with the macro system in 2.10.
As I note in a comment above, this approach requires index to be an integer literal, and relies on "underspecified but intended" behavior in 2.10. It also raises some tricky questions about documentation.
import scala.language.experimental.macros
import scala.reflect.macros.Context
object ProductIndexer {
def at[T <: Product](t: T)(index: Int) = macro at_impl[T]
def at_impl[T <: Product: c.WeakTypeTag](c: Context)
(t: c.Expr[T])(index: c.Expr[Int]) = {
import c.universe._
index.tree match {
case Literal(Constant(n: Int)) if
n >= 0 &&
weakTypeOf[T].members.exists {
case m: MethodSymbol => m.name.decoded == "_" + (n + 1).toString
case _ => false
} => c.Expr[Any](Select(t.tree, newTermName("_" + (n + 1).toString)))
case Literal(Constant(_: Int)) => c.abort(
c.enclosingPosition,
"There is no element at the specified index!"
)
case _ => c.abort(
c.enclosingPosition,
"You must provide an integer literal!"
)
}
}
}
And then:
scala> import ProductIndexer._
import ProductIndexer._
scala> val triple = (1, 'a, "a")
triple: (Int, Symbol, String) = (1,'a,a)
scala> at(triple)(0)
res0: Int = 1
scala> at(triple)(1)
res1: Symbol = 'a
scala> at(triple)(2)
res2: String = a
All statically typed as expected, and if you give it an index that's out of range (or not a literal), you get a nice compile-time error.
You cannot do that. If you use Product, the (compile-time) type of the values in the tuples is lost. Further, a method cannot adapt its return type based on an value you pass in (not entirely true, see dependent method types, but true for an Int).
If you do not know what type to cast to, you could use pattern matching:
subscript_get(..., 1) match {
case v: Int => // do something with Int
case v: String => // do something with String
// snip
case _ => sys.error("don't know how to handle this")
}