How to define a function in scala for flatMap - scala

New to Scala, I want to try to rewrite some code in flatMap by calling a function instead of writing the whole process inside "()".
The original code is like:
val longForm = summary.flatMap(row => {
/*This is the code I want to replace with a function*/
val metric = row.getString(0)
(1 until row.size).map{i=>
(metric,schema(i).name,row.getString(i).toDouble)
})
}/*End of function*/)
The function I wrote is:
def tfunc(line:Row):List[Any] ={
val metric = line.getString(0)
var res = List[Any]
for (i<- 1 to line.size){
/*Save each iteration result as a List[tuple], then append to the res List.*/
val tup = (metric,schema(i).name,line.getString(i).toDouble)
val tempList = List(tup)
res = res :: tempList
}
res
}
The function did not passed compilation with the following error:
error: missing argument list for method apply in object List
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing apply _ or apply(_) instead of apply.
var res = List[Any]
What is wrong with this function?
And for flatMap, is it the write way to return the result as a List?

You haven't explained why you want to replace that code block. Is there a particular goal you're after? There are many, many, different ways that block could be rewritten. How can we know which would be better at meeting you requirements?
Here's one approach.
def tfunc(line :Row) :List[(String,String,Double)] ={
val metric = line.getString(0)
List.tabulate(line.tail.length){ idx =>
(metric, schema(idx+1).name, line.getString(idx+1).toDouble)
}
}

Related

unable to convert a java.util.List into Scala list

I want that the if block returns Right(List[PracticeQuestionTags]) but I am not able to do so. The if/else returns Either
//I get java.util.List[Result]
val resultList:java.util.List[Result] = transaction.scan(scan);
if(resultList.isEmpty == false){
val listIterator = resultList.listIterator()
val finalList:List[PracticeQuestionTag] = List()
//this returns Unit. How do I make it return List[PracticeQuestionTags]
val answer = while(listIterator.hasNext){
val result = listIterator.next()
val convertedResult:PracticeQuestionTag = rowToModel(result) //rowToModel takes Result and converts it into PracticeQuestionTag
finalList ++ List(convertedResult) //Add to List. I assumed that the while will return List[PracticeQuestionTag] because it is the last statement of the block but the while returns Unit
}
Right(answer) //answer is Unit, The block is returning Right[Nothing,Unit] :(
} else {Left(Error)}
Change the java.util.List list to a Scala List as soon as possible. Then you can handle it in Scala fashion.
import scala.jdk.CollectionConverters._
val resultList = transaction.scan(scan).asScala.toList
Either.cond( resultList.nonEmpty
, resultList.map(rowToModel(_))
, new Error)
Your finalList: List[PracticeQuestionTag] = List() is immutable scala list. So you can not change it, meaning there is no way to add, remove or do change to this list.
One way to achieve this is by using scala functional approach. Another is using a mutable list, then adding to that and that list can be final value of if expression.
Also, a while expression always evaluates to Unit, it will never have any value. You can use while to create your answer and then return it seperately.
val resultList: java.util.List[Result] = transaction.scan(scan)
if (resultList.isEmpty) {
Left(Error)
}
else {
val listIterator = resultList.listIterator()
val listBuffer: scala.collection.mutable.ListBuffer[PracticeQuestionTag] =
scala.collection.mutable.ListBuffer()
while (listIterator.hasNext) {
val result = listIterator.next()
val convertedResult: PracticeQuestionTag = rowToModel(result)
listBuffer.append(convertedResult)
}
Right(listBuffer.toList)
}

How to convert a class T object into a Future[T] object in akka

I am trying to do something with akka and scala and i am new to it. I want to append the result of an 'Any' Future into one of the fields in the class
So i have class called T defined as
class T {
var a: String =_
var result = List[Any]= List()
}
Now i have a variable which receives a future value
var futureResult:Future[Any] = //receives a future value
in a function called addResult which takes an T object and returns a future T object.
def addResult(obj1:T):Future[T] ={
var obj2:T = new T()
obj2.a = obj1.a
obj2.result = obj1.result
//I want to append results of futureResult into obj2.result when it is completed
// obj2.result = futureResult :: obj2.result
return Future(obj2)
}
I have to finally call this function from a flow.
val b = Flow[T].mapAsync[T](1)(addResult(_))
First, as #riccardo.cardin noted using T as a name of a class is very bad idea, because of T usual points to generic.
However, you can put any logic in Future with a simple closure, in your case, it looks like this:
Future {
new T("some string", 1 :: 2 :: 3 :: Nil)
}
After that, you can combine asynchronous computation via flatMap, map or with for comprehensive or even use cats black magic with |#|:
for {
f1 <- future1()
f2 <- future2(f1.id)
} yield f2.name
(future1 |#| future2) map { _ - _ }
In your case this transformation depends from logic of your code.
You can change the commented line like this:
futureResult.map { res =>
obj2.result = res :: obj2.result
obj2
}
And then you won't need the last line.

Found Unit, required Int

I have the following Scala code:
object Solution {
def getBestSolution(sumList: List[Int]): Int = {
return 0
}
def main(args: Array[String]) {
val t = readInt()
(0 until t).foreach({
val n = readInt()
val a = readLine().split(" ").map(_.toInt).toList
val sumList = a.scanLeft(0)(_ + _).tail.toList
//println(classOf[sumList])
println(sumList)
println(getBestSolution(sumList))
})
}
}
For it, I am getting this error:
file.scala:16: error: type mismatch;
found : Unit
required: Int => ?
println(getBestSolution(sumList))
^
one error found
Any idea what is causing this?
The argument you are passing to foreach is the result of executing the code block (which is a Unit), not a function.
Remove the outer parentheses (they do not really hurt anything, but are unnecessary and look ugly), and add _ => in the beginning:
(0 to t).foreach { _ =>
...
println(getBestSolution(sumList))
}
This is the proper syntax for creating an unnamed function. The stuff before => is the parameter list that the function accepts. In your case, you can just put an underscore there, because you do not need the value of the parameter. Or you could give it a name if you needed to do something with it, e.g.: (0 to t).foreach { x => println(x*x) }
you could have done it with simple for comprehension too instead of foreach
for(x <- 0 to t){
val n = readInt()
val a = readLine().split(" ").map(_.toInt).toList
val sumList = a.scanLeft(0)(_ + _).tail.toList
//println(classOf[sumList])
println(sumList)
println(getBestSolution(sumList))
}
To sum up, Programming in Scala book has pointed that Scala provides the for comprehension, which provides syntactically pleasing nesting of map, flatMap, and filter ... The for comprehension is not a looping construct, but is a syntactic construct the compiler reduces to map, flatMap, and filter.

Flatten long nesting of Monadic types in Scala

I have a function to get a seq of workItemIds given JobIds, with following signature -
def getWorkItemIds(jobId: JobId): Future[Seq[WorkItemId]]
I have another function which given a WorkItemId would return a workItem. with signature -
def getWorkItem(workItemId: WorkItemId): Future[Option[WorkItem]]
Now I am trying to write a function which uses these two to return a seq of WorkItem given a JobId, like this -
def getWorkItemsForJob(jobId: JobId): Future[Seq[Future[Option[WorkItem]]]] = {
val workItemIds: Future[Seq[WorkItemId]] = getWorkItemIds(jobId)
val res = workItemIds.map {
idSeq => idSeq.map {
id => getWorkItem(id)
}
}
res
}
The problem is the return type, I don't want to return this monstrous type, instead something simpler like a Future[Seq[WorkItem]] should be returned. Now I can flatten it like -
def getWorkItemsForJob(jobId: JobId): Future[Seq[WorkItem]] = {
val workItemIds: Future[Seq[WorkItemId]] = getWorkItemIds(jobId)
val res = workItemIds.map {
idSeq => idSeq.flatMap {
id => getWorkItem(id).get
}
}
res
}
which gives me the correct Future[Seq[WorkItem]] type that I want, but it requires me to do a get on the future, which does not feel correct. I can also use await but that would be a blocking call. Is there anyway to flatten the above type without blocking ?
What you are looking for is Future.traverse:
def getWorkItemsForJob(jobId: JobId): Future[Seq[WorkItem]] =
getWorkItemIds(jobId).flatMap(Future.traverse(_)(getWorkItem).map(_.flatten))
The .traverse call takes the Seq from the getWorkItemIds call and returns a Future[Seq] of the results of calling getWorkItem on each entry, without the inner Future wrapping.
The .map(_.flatten) near the end flattens out this inner Seq[Option[WorkItem]] to just Seq[WorkItem].
You can do it the following way:
def getWorkItemsForJob(jobId: JobId): Future[Seq[WorkItem]] =
for (
seq <- getWorkItemIds(jobId);
list <- Future.traverse(seq)(getWorkItem)
) yield list.flatten

How to return a value from a Scala def

I am new to Scala, but have some experience with Haskell. I did the following:
import scala.io.Source
val fileContent = Source.fromFile(filename).getLines.toList
val content = fileContent.map(processLine)
def processLine(line: String){
val words = line.split("\\s+")
println((words(0), words(1)))
}
Here processLine doesn't return anything so content is now a list of empty return values for all items. I thought the solution would be to include a return value in processLine, but Scala doesn't like that:
warning: enclosing method processLine has result type Unit: return value discarded
So how can I modify processLine so that it can be used to create a list of non-empty tuple values in content? how would it be to declare a lambda function with more than one line?
Thanks to helpful info in this thread, I could also have written it with a lambda expression:
var nonLinearTrainingContent = fileContent.map(x=> {
val words = x.split("\\s+")
(words(0), words(2))
})
There are two things that prevent a result being returned:
println returns Unit
Your function defintion is a shorthand for a method returning Unit
This would give you the result you expected:
def processLine(line: String) : (String,String) = {
val words = line.split("\\s+")
val result = (words(0), words(1))
println(result)
result
}
As asked the same expressed as a function:
val processLineFun : String => (String, String) = line => {
val words = line.split("\\s+")
val result = (words(0), words(1))
println(result)
result
}
Make the tuple (words(0), words(1)) the last line of processLine function:
def processLine(line: String) = {
val words = line.split("\\s+")
println((words(0), words(1)))
(words(0), words(1))
}
Edit: use curly braces for multiline lambda function or separate operators with ';' for one-line lambda
Edit2: fixed return type