Scala: Use map function tuples in a subsequent flatMap - scala

I want to use a tuple of a map function in a subsequent flatMap.
Like this:
val list = orders.map(ord => (ord.prod.tasks, ord.quantity))
.zipWithIndex flatMap {
case (variable, index) =>
createSchedules(variable._1.size * variable._2, ord, null)
}
Is there a way in which I can use it or do you think that I have to change the way that I'm thinking about the solution?

I want to use a tuple of a map function in a subsequent flatMap.
Here's a working example of using tuples in a subsequent flatMap
val input = List("a", "b", "c")
val list = input.map(i => (i + "A", i + "B")).zipWithIndex flatMap{ case (variable, index)=> variable._1 + variable._2}
Issue with original code
val list = orders.map(ord => (ord.prod.tasks, ord.quantity)).zipWithIndex flatMap{case (variable, index)=>createSchedules(variable._1.size * variable._2, ord, null)}
One issue is that ord is out of scope in the 'createSchedules' call.
ord will only be visible in the initial 'orders.map' scope.

First of all, judging from the parameters that you're passing to createSchedules, it looks as if that function can be simplified to (I'm ignoring the null parameter for now):
def createSchedules(order: Order): List[Schedule] = {
val num = order.prod.tasks.size * order.quantity
// do stuff
}
Also, the initial map is unnecessary. list can be simplified to:
val list = orders.zipWithIndex
.flatMap {
case (order, index) =>
createSchedules(order)
}
It's unclear what you need the index for, though.

Related

Reducing/Folding a List of Strings to a Map[String,Boolean] in Scala

I have a list like this:
val objectKeys = List("Name","Place","Animal","Thing");
I want to reduce it to a Map[String,Boolean] where Boolean is element.size < 8.
Here's what I wrote:
val mappedObject = objectKeys.fold(Map[String,Boolean])((map,key) => map + (key -> key.size < 8))
which gives me the following error:
value + is not a member of Object, but could be made available as an extension method.
and
value size is not a member of Object
My understanding about fold is that it takes a default argument and reduces the entire value around it which however doesn't seem to work in this case. Can anyone help me with this?
Ideally mappedObject should be like:
val mappedObject = Map[String,Boolean]("Name"->true,"Place"->true,"Animal"->true,"Thing"->true)
An equivalent Javascript implementation will be:
const listValues = ["Name","Place","Animal","Thing"];
const reducedObject = listValues.reduce((acc,curr) => {acc[curr] = curr.length < 8;
return acc;
},{});
If you really want to do it with a fold, that's easy to do:
objectKeys.foldLeft(Map.empty[String, Boolean]) { (acc, key) =>
acc + ((key, key.length < 8))
}
That said, I'm with Ivan on this one. map is clearly the better solution here (or fproduct if you're using the cats library).
I think in this case you should just map to a tuple containing your key with boolean check and then convert it to Map[String, Boolean] via toMap method as following.
objectKeys.map(key => (key, key.length < 8)).toMap

How to create listBuffer in collect function

I tought that List is enough but I need to add element to my list.
I've tried to put this in ListBuffer constructor but without result.
var leavesValues: ListBuffer[Double] =
leaves
.collect { case leaf: Leaf => leaf.value.toDouble }
.toList
Later on I'm going to add value to my list so my expected output is mutable list.
Solution of Raman Mishra
But what if I need to append single value to the end of leavesValues
I can reverse but it's not good enough
I can use ListBuffer like below but I believe that there is cleaner solution:
val leavesValues: ListBuffer[Double] = ListBuffer()
leavesValues.appendAll(leaves
.collect { case leaf: Leaf => leaf.value.toDouble }
.toList)
case class Leaf(value:String)
val leaves = List(Leaf("5"), Leaf("6"), Leaf("7"), Leaf("8") ,Leaf("9") )
val leavesValues: List[Double] =
leaves
.collect { case leaf: Leaf => leaf.value.toDouble }
val value = Leaf("10").value.toDouble
val answer = value :: leavesValues
println(answer)
you can do it like this after getting the list of leavesValues you can prepand the value you want to add into the list.

Decompose Scala sequence into member values

I'm looking for an elegant way of accessing two items in a Seq at the same time. I've checked earlier in my code that the Seq will have exactly two items. Now I would like to be able to give them names, so they have meaning.
records
.sliding(2) // makes sure we get `Seq` with two items
.map(recs => {
// Something like this...
val (former, latter) = recs
})
Is there an elegant and/or idiomatic way to achieve this in Scala?
I'm not sure if it is any more elegant, but you can also unpick the sequence like this:
val former +: latter +: _ = recs
You can access the elements by their index:
map { recs => {
val (former, latter) = recs(0), recs(1)
}}
You can use pattern matching to decompose the structure of your list:
val records = List("first", "second")
records match {
case first +: second +: Nil => println(s"1: $first, 2: $second")
case _ => // Won't happen (you can omit this)
}
will output
1: first, 2: second
The result of sliding is a List. Using a pattern match, you can give name to these elements like this:
map{ case List(former, latter) =>
...
}
Note that since it's a pattern match, you need to use {} instead of ().
For a records of known types (for example, Int):
records.sliding (2).map (_ match {
case List (former:Int, latter:Int) => former + latter })
Note, that this will unify element (0, 1), then (1, 2), (2, 3) ... and so on. To combine pairwise, use sliding (2, 2):
val pairs = records.sliding (2, 2).map (_ match {
case List (former: Int, latter: Int) => former + latter
case List (one: Int) => one
}).toList
Note, that you now need an extra case for just one element, if the records size is odd.

How to use map / flatMap on a scala Map?

I have two sequences, i.e. prices: Seq[Price] and overrides: Seq[Override]. I need to do some magic on them yet only for a subset based on a shared id.
So I grouped them both into a Map each via groupBy:
I do the group by via:
val pricesById = prices.groupBy(_.someId) // Int => Seq[Cruise]
val overridesById = overrides.groupBy(_.someId) // // Int => Seq[Override]
I expected to be able to create my wanted sequence via flatMap:
val applyOverrides = (someId: Int, prices: Seq[Price]): Seq[Price] => {
val applicableOverrides = overridesById.getOrElse(someId, Seq())
magicMethod(prices, applicableOverrides) // returns Seq[Price]
}
val myPrices: Seq[Price] = pricesById.flatMap(applyOverrides)
I expected myPrices to contain just one big Seq[Price].
Yet I get a weird type mismatch within the flatMap method with NonInferedB I am unable to resolve.
In scala, maps are tuples, not a key-value pair.
The function for flatMap hence expects only one parameter, namely the tuple (key, value), and not two parameters key, value.
Since you can access first element of a tuple via _1, the second via _2 and so on, you can generate your desired function like so:
val pricesWithMagicApplied = pricesById.flatMap(tuple =>
applyOverrides(tuple._1, tuple._2)
Another approach is to use case matching:
val pricesWithMagicApplied: Seq[CruisePrice] = pricesById.flatMap {
case (someId, prices) => applyOverrides(someId, prices)
}.toSeq

Removing Try failures in collection using flatMap

I have a Map[String, String]
How can I simply this expression using flatMap?
val carNumbers = carMap.keys.map(k => Try(k.stripPrefix("car_number_").toInt)).toList.filter(_.isSuccess)
Note: I want to remove the Failure/Success wrapper and just have a List[Int].
It looks like you just want to convert Try to Option:
for {
key <- carMap.keys
t <- Try(key.stripPrefix("car_number_").toInt).toOption
} yield t
this will result Iterable and you can convert it to list with .toList method.
Also you can go with oneliner like this:
carMap.keys.flatMap(k => Try(k.stripPrefix("car_number_").toInt).toOption)
Consider using collect() with a partial function:
carMap.keys
.collect( k =>
Try(k.stripPrefix("car_number_").toInt) match {
case Success(num) => num
}
)
This will return an Iterable[Int] with the values that could be stripped and converted to an Int (assuming this is what you were looking for).