I am getting compile error when trying to map list of tuples. I have a method which return Future[List[(String, String)]] and I need to use those two set of String value to make a call to another method
def myHelper(): Future[List[(String, String)]] = { ... }
def myWork() = {
myHelper() map {
case(firstVal, secondVal) => otherWork(firstVal, secondVal)
}
}
Error I am getting is
found: (T1, T2)
required: List[(String, String)]
Any suggestion?
EDIT
hmm .... I wasn't clear about my question. otherWork expect list of all result
def otherWork(firstVals: List[String], secondVals: List[Strong]) = { ... }
Let's implement the myWork function as:
def myWork = myHelper.map {
helper => (otherWork _).tupled(helper.unzip)
}
Depends on what you want to do.
Call otherWork on every tuple?
def myWork() = {
myHelper().map(_.map {
case (firstVal, secondVal) => otherWork(firstVal, secondVal)
})
}
If otherWork: (String, String) => T, then myWork: () => Future[List[T]].
If otherWork: (String, String) => Future[T] and you want to run them all and collect the results, then you can use something like
def myWork() = {
myHelper() flatMap { list => Future.sequence(
list map { case (firstVal, secondVal) =>
otherWork(firstVal, secondVal)
})
}
}
With the question clarification, you want unzip.
def myWork() = {
myHelper() map { list =>
list.unzip match {
case (firstVals, secondVals) => otherWork(firstVals, secondVals)
}
}
}
Federico Pellegatta's answer has a shorter form of writing this.
Related
I have this function in Scala:
def printA(A: Array[_]): Unit = {
if (A.isInstanceOf[Array[Int]]) A.foreach(t => println(t))
else A.foreach(a => printA(a))
}
I don't know, how to fix this error, that printA(a) is Any. The function accepts input Array[_]
Thanks, guys!
Maybe, it is better to check an element instead of an array?
def printA(array: Array[_]): Unit = {
array.foreach {
case i: Int => println(i)
case arr: Array[_] => printA(arr)
case unknown => sys.error("Unsupported element: "+unknown)
}
}
I wrote this
def computeMap(map:Map[String, DataFrame], f: (String) => String, g: (DataFrame) => DataFrame ) : Map[String, DataFrame] = {
map.map{ case (key, value) => (f(key), g(value) }
}
My problem here is that f and g function are provided by 2 implicit classes wrapped in objects ( one implicit class for string transform and the second one is for dataframe transorm)
I rather want to write:
def computeMap(map:Map[String, DataFrame], f: tobecompleted, g: tobecompleted ) : Map[String, DataFrame] = {
map.map{ case (key, value) => (key.f, value.g) }
}
f for example can be defined
object Test {
implicit class Transform(s:String) {
def colm():String = {
s + "ded"
}
}
Is there any solution for this please ?
I have a method that processes a Source and returns. I am trying to modify it but can't seem to be able to return the same thing:
Original
def originalMethod[as: AS, mat: MAT, ec: EC](checkType: String)
: Flow[ByteString, MyValidation[MyClass], NotUsed]{
collectStuff
.map { ts =>
val errors = MyEngine.checkAll(ts.code)
(ts, errors)
}
.map { x =>
x._2
.leftMap(xs => {
addInformation(x._1, xs.toList)
})
.toEither
}
}
I am modifying by using another source and pass result of that to the original source and yet return the same thing:
def calculate[T: AS: MAT](source: Source[T, NotUsed]): Future[Seq[T]] =
{
source.runWith(Sink.seq)
}
def modifiedMethod[as: AS, mat: MAT, ec: EC](checkType: String, mySource: Source[LoanApplicationRegister, NotUsed])
: Flow[ByteString, MyValidation[MyClass], NotUsed]{
for {
calc <- calculate(mySource)
orig <- collectStuff
.map { ts =>
val errors = MyEngine.checkAll(ts.code, calc)
(ts, errors)
}
.map { x =>
x._2
.leftMap(xs => {
addInformation(x._1, xs.toList)
})
.toEither
}
}
yield {
orig
}
}
But I'm getting compilation error Expression of type Future[Nothing] doesn't conform to existing type Flow[ByteString, MyValidation[MyClass]
How can I return Flow[ByteString, MyValidation[MyClass] in my modifiedMethod just like the originalMethod was
for { calc <- calculate(mySource)}
yield {
collectStuff
.map { ts =>
val errors = MyEngine.checkAll(ts.code, calc)
(ts, errors)
}
.map { x =>
x._2
.leftMap(xs => {
addInformation(x._1, xs.toList)
})
.toEither
}
}
would give you a Future[Flow[ByteString, MyValidation[MyClass], NotUsed]] instead of Future[Nothing]
but if you want to remove the Future you'd need to Await somewhere for it (either when you call calculate (and then you don't need the for) or after it. Usually, that's not the way to use Futures
def myMethod(myType: String) :Future[Future[Either[List[MyError], MyClass]]] {
for {
first <- runWithSeq(firstSource)
}
yield {
runWithSeq(secondSource)
.map {s ->
val mine = MyClass(s.head, lars)
val errors = myType match {
case "all" => Something.someMethod(mine)
}
(s, errors)
}
.map { x =>
x._2.leftMap(xs => {
addInfo(x._1.head, xs.toList)
}).toEither
}
}
}
for {
myStuff <- myMethod("something")
} yield {
myStuff.collect {
case(Left(errors), rowNumber) =>
MyCaseClass(errors, None) //compilation error here
}
}
I get compilation error on MyCaseClass that expected: List[MyError], found: Any
The signature of MyCaseClass is:
case class MyCaseClass(myErrors: List[ValidationError])
How can I fix this such that I can correctly call MyCaseClass inside the yield?
Your code example doesn't make much sense, and doesn't compile, but if runWithSeq() returns a Future then you should be able to eliminate the double Future return type like so.
for {
_ <- runWithSeq(firstSource)
scnd <- runWithSeq(secondSource)
} yield { ...
Your example is pretty hard to paste and fix
Abstact example for this
Class C may be whatever you want
def test(testval: Int)(implicit ec: ExecutionContext): Future[Future[Either[String, Int]]] = {
Future(Future{
if (testval % 2 == 0) Right(testval) else Left("Smth wrong")
})
}
implicit class FutureEitherExt[A, B](ft: Future[Either[A, B]]) {
def EitherMatch[C](f1: A => C, f2: B => C)(implicit ec: ExecutionContext): Future[C] = {
ft.map {
case Left(value) => f1(value)
case Right(value) => f2(value)
}
}
}
val fl: Future[Either[String, Int]] = test(5).flatten
val result: Future[String] = fl.EitherMatch(identity, _.toString)
I have a function in my controller like this:
def getPreviousVersions(id: Int): Action[AnyContent] = Action.async {
val result: Future[Option[ElementModel]] = dto.getPreviousVersion(id)
// while-loop or whatever is best practice
// val arrayOfElements: Future[Seq[ElementModel] = ...
val c = for {
previousVersions <- arrayOfElements
} yield previousVersions
//do something with the versions
//Return something in the end
}
My model looks like this:
case class ElementModel(
...
previousVersion: Option[Int],
...)
I store the id of the latest previousVersion in my model. Now, what I want to do is iterate either recursively or with a while-loop or whatever is best-practice to get the previousVersion of the previousVersion and so on.
The idea is to get all previous versions, store them in a sequence and pass this seq to another function.
Is there a smooth, proper way to do this? Thanks!
def getVersionSequence(id: Int): Future[List[ElementModel]] = {
def _getVersionSequence(id: Int, fList: Future[List[ElementModel]]): Future[List[ElementModel]] = {
dto.getPreviousVersion(id).flatMap({
case Some(elementModel) => elementModel.previousVersion match {
case Some(pVId) => _getVersionSequence(pVId, fList.map(list => elementModel +: list))
case None => fList.map(list => elementModel +: list)
}
case None => fList
})
}
val fInvertedList = _getVersionSequence(id, Future(List.empty[ElementModel]))
fInvertedList.map(list => list.reverse)
}
def getPreviousVersions(id: Int): Action[AnyContent] = Action.async {
val c: Future[List[ElementModel]] = getVersionSequence(id)
//do something with the versions
//Return something in the end
}
def getPreviousVersion(previousVersionId: Int): Future[ElementModel] = dto.getElementModelForId(previousVersionId)
/*This has been changed from your question, you shouldn't need a getPreviousVersion(id) function in your database connector, but merely a function to get an element by id*/
def getAllPreviousVersions(e: ElementModel): Future[Seq[ElementModel]] = {
e.previousVersion match {
case None => Future.successful(Seq(e))
case Some(id) => getPreviousVersion(id).flatMap {
previousVersionElement =>
getAllPreviousVersions(previousVersionElement).map {
//Properly preserves order !
seq => previousVersionElement +: seq
}
}
}
}
def getPreviousVersions(e: ElementModel) = {
getAllPreviousVersions(e).map {
//do something with the versions
//Return something in the end
???
}
}