I have a file, each row is a json array. I reading each line of the file, and trying to convert the rows into a json array, and then for each element I am converting to a case class using json spray.
I have this so far:
for (line <- source.getLines().take(10)) {
val jsonArr = line.parseJson.convertTo[JsArray]
for (ele <- jsonArr.elements) {
val tryUser = Try(ele.convertTo[User])
}
}
How could I convert this entire process into a single line statement?
val users: Seq[User] = source.getLines.take(10).map(line => line.parseJson.convertTo[JsonArray].elements.map(ele => Try(ele.convertTo[User])
The error is:
found : Iterator[Nothing]
Note: I used Scala 2.13.6 for all my examples.
There is a lot to unpack in these few lines of code. First of all, I'll share some code that we can use to generate some meaningful input to play around with.
This is just some scaffolding to define some
Userdomain object and come up with a way to generate a JSON representation of an array of such objects so that we can then use a JSON library (spray-jsonin this case) to parse it back into what we want.Now, going back to your question. This is a possible way to massage your data into its parsed representation. It may not fit 100% what your are trying to do, but there's some nuance in the data types involved and how they work:
First difference: notice that I use the
forcomprehension in a form in which the "outcome" of an iteration is not a side effect (for (something) { do something }) but an actual valuefor (something) yield { return a value }).Second difference: I explicitly asked for an
Iterator[Try[User]]rather than aSeq[User]. We can go very down into a rabbit hole on the topic of why the types are what they are here, but the simple explanation is that afor ... yieldexpression:val ns: Iterator[Int]; for (n<- ns) ...you'll get an iterator at the endYou can read more on
forcomprehensions on the Tour of Scala and the Scala Book.One possible way of consuming this is the following:
As for how to turn this into a "one liner",
forcomprehensions are syntactic sugar applied by the compiler which turns every nested call into aflatMapand the final one intomap, as in the following example (which yields an equivalent result as theforcomprehension above and very close to what the compiler does automatically):One note that I would like to add is that you should be mindful of readability. Some teams prefer
forcomprehensions, others manually rolling out their ownflatMap/mapchains. Coders discretion is advised.You can play around with this code here on Scastie (and here is the version with the
flatMap/mapcalls).