map to form select Scala Play2 using reactivemongo - scala

I have in a Play2 Template:
files: Option[List[(String, reactivemongo.api.gridfs.ReadFile[reactivemongo.bson.BSONValue])]]
I would like to display the files in a drop down form Select, but only if the files are there!
How would I do this?

As Julien Lafont said, you should consider transforming this list before giving it to your template. For example if you just want a list of read files (on which you can call filename and id):
val fileList = files.toList.flatten.map(_._2) // fileList is a List[ReadFile[BSONValue]]]
And if you want just want to get filenames and their ids (given that their ids are BSONObjectIDs), you may write this:
val fileList = files.toList.flatten.map { file =>
val id = file._2.id match {
case oid: BSONObjectID => oid.stringify
case id => id.toString
}
id -> file._2.filename
}
// fileList is a List[(String, String)] where the first element of the tuple is a string version of the id and the second is the name of the file.

Related

How to create a map for (key - image name // value - image-file) in Scala

def getListOfImageNames(dir: String): List[String] = {
val names = new File(dir)
names.listFiles.filter(_.isFile)
.map(_.getName).toList
}
def getListOfImages(dir: String): List[String] = {
val files = new File(dir)
files.listFiles.filter(_.isFile)
.filter(_.getName.endsWith(".png"))
.filter(_.getName.endsWith(".jpg"))
.map(_.getPath).toList
}
I have a directory where I have different photos, small size, large size and I have already managed to write methods which: one of them only pulls out the names of the photos and the other the photos. How can I now combine them into a map, for example, then calculate their resolution using the method, if the photo is larger than, for example, 500x500, add a prefix to the name and save it in the X folder. Do you have any ideas? I'm not experienced in Scala, but I like the language very much.
As I got you need to get map of image name to image path. You can achieve it like so:
def getImagesMap(dirPath: String): Map[String, String] = {
val directory = new File(dirPath)
directory.listFiles.collect{
case file if file.isFile &&
(file.getName.endsWith(".png") ||
file.getName.endsWith(".jpg")) =>
file.getName -> file.getPath
}.toMap
}
here I use collect function. It's like combination of map and filter functions. Inside collect a pattern matching expression. If file matches pattern matching it will evaluate pair creation: file name to file path. Otherwise file just will be filtered. After I use toMap for conversion Array[(String, String)] to Map[String, String]. You can read more about collect here.

Scala: Swapping two key values in a collection?

I have a val pointing to a big collection of records that were read from a file in HDFS. Let's call this val 'a'. 'a' has a bunch of records that all contain these 3 properties: SRC, DEST, ACT. I need to make a clone of 'a', but have the values of SRC and DEST keys swapped in each record. How do I go about doing this in scala? I've tried different variants of the map function but can't seem to get this to work correctly.
Well, without a code example, I am guessing at your needs and prerequisites, but something like this could work:
case class Record(src: String, dest: String, act: String)
val a = List(
Record("srcA", "destA", "actA"),
Record("srcB", "destB", "actB"),
Record("srcC", "destC", "actC"),
Record("srcD", "destD", "actD"),
Record("srcE", "destE", "actE"),
)
val b = a.map(r => Record(r.dest, r.src, r.act))
println(a)
// => List(Record(srcA,destA,actA), Record(srcB,destB,actB), Record(srcC,destC,actC), Record(srcD,destD,actD), Record(srcE,destE,actE))
println(b)
// => List(Record(destA,srcA,actA), Record(destB,srcB,actB), Record(destC,srcC,actC), Record(destD,srcD,actD), Record(destE,srcE,actE))

Iterate through complex Scala collections loaded from config file

I've read other threads on SO about iterating through collections from config files in Scala but they always assume the type in question is either a ConfigList or an ObjectList. In my case it is a more complex structure and I could not figure out how to access its elements.
In my config file I need to have a group of tuples without being too finicky on the collection type. For instance, I'm open to use a List of tuples or a Map[String, List], etc. Like the following (from application.conf):
myprogr {
groupsOfSomeStuff
{
group_1 -> {
name = "name1",
url = "url1",
something = "whatever"
},
...,
group_n -> {
name = "namen",
url = "urln",
something = "whatever"
}
}
}
At the moment with the conf file above, I can only print the whole groupsOfSomeStuff but I can not access any of its individual elements:
var conf = ConfigFactory.load()
println(conf.getObject("myprogr.groupsOfSomeStuff"))
which returns:
SimpleConfigObject({"group_1 ->":{"something":"whatever","name":"name1","url":"url1"}, ..., "group_n ->":{"something":"whatever","name":"namen","url":"urln"})
If I try to print conf.getObjectList or conf.getConfList I get an error at run time cause what gets extracted from the conf file is not a list but an object. The same happens if I substitute the "->" in the conf file with ":" or with "=" (since as I wrote, I'm open to different types of collections).
If I try to assign conf.getObject("myprogr.groupsOfSomeStuff") to a var of type SimpleConfigObject (with the intention of iterate through the elements of its "value" Map attribute), I get a compile-time error "SimpleConfigObject is not accessible from this position".
How can I iterate through the group_1, ..., group_n elements and individually access the name, url and something parts of each entry's value?
Thanks a million in advance! ;)
object TestConfig extends App {
import scala.collection.JavaConverters._
case class Foo(name: String, url: String, something: String)
val config = ConfigFactory.parseResources("test.conf")
val path = "myprogr.groupsOfSomeStuff"
val fooList: List[Foo] = config.getObject(path).keySet().asScala.map { key =>
val member = config.getObject(s"$path.$key").toConfig
Foo(member.getString("name"), member.getString("url"), member.getString("something"))
}.toList
println(fooList)
}
It should print List(Foo(name1,url1,whatever), Foo(namen,urln,whatever))
I hope this is what you are trying to do.

Scala - Expanding an argument list in a pattern matching expression

I'm very new to Scala and trying to use it as an interface to Spark. I'm running into a problem making a generic CSV to DataFrame function. For example, I've got a CSV with about 50 fields, the first of which are task, name, and id. I can get the following to work:
val reader = new CSVReader(new StringReader(txt))
reader.readAll().map(_ match {
case Array(task, name, id, _*) => Row(task, name, id)
case unexpectedArrayForm =>
throw new RuntimeException("Record did not have correct number of fields: "+ unexpectedArrayForm.mkString(","))
})
However, I'd rather not have to hard code the number of fields needed to create a spark Row. I tried this:
val reader = new CSVReader(new StringReader(txt))
reader.readAll().map(_ match {
case Array(args # _*) => Row(args)
case unexpectedArrayForm =>
throw new RuntimeException("Record did not have correct number of fields: "+ unexpectedArrayForm.mkString(","))
})
But it just creates a Row object with a single element. How can I make it expand the args in Row(args) so that if I have an array of N elements I'll get a Row with N elements?
Change your input to be variable length by adding _*:
Row(args:_*)
This is what Row accepts per its apply signature.
In fact, you don't even need to do anything other than pass this in to the Row as it is already of the right sequence type.
reader.readAll().map(Row(_:_*))
This should do the trick:
val reader = new CSVReader(new StringReader(txt))
reader.readAll().map(_ match {
case a: Array[String] => Row(a:_*)
case unexpectedArrayForm =>
throw new RuntimeException("Record did not have correct number of fields: "+ unexpectedArrayForm.mkString(","))
})
Edited to correct omission of Array type

Specs2 JSONMatchers: mapping over Array elements?

I'm using the Specs2 JSONMatcher to validate that a GET request is being correctly converted from its internal representation (there are some manipulations we do before generating the JSON). What I need to do is, make sure that an element in the JSON array matches the corresponding object from our repository.
What I've tried:
val response = response.entity.asString // Spray's way of getting the JSON response
repository.all.map { obj =>
resp must */ ("id" -> obj.id)
resp must */ ("state" -> generateState(obj)
}
The problem is that the */ matcher just finds that "state": "whatever" (assuming generateState returns "whatever") exists somewhere in the JSON document, not necessarily in the same one matched by the ID
I tried using the indices but the repository.all method doesn't always return the elements in the same order, so there's no way of matching by index.
What I'd like to do is, iterate over the elements of the JSON array and match each one separately. Say an /## operator (or something) that takes matchers for each element:
resp /## { elem =>
val id = elem("id")
val obj = repository.lookup(id)
elem /("state" -> generateState(obj))
}
Does anyone have a way to do this or something similar?
Probably the easiest thing to do for now (until a serious refactoring of JsonMatchers) is to do some parsing and recursively use a JsonMatchers in a Matcher[String]:
"""{'db' : { 'id' : '1', 'state' : 'ok_1'} }""" must /("db" -> stateIsOk)
// a string matcher for the json string in 'db'
def stateIsOk: Matcher[String] = { json: String =>
// you need to provide a way to access the 'id' field
// then you can go on using a json matcher for the state
findId(json) must beSome { id: String =>
val obj = repository.lookup(id)
json must /("state" -> generate(obj))
}
}
// I am using my own parse function here
def findId(json: String): Option[String] =
parse(json).flatMap { a =>
findDeep("id", a).collect { case JSONArray(List(v)) => v.toString }
}
// dummy system
def generate(id: String) = "ok_"+id
case object repository {
def lookup(id: String) = id
}
What I did in the end is use responseAs[JArray], JArray#arr and JObject#values to convert the JSON structures into Lists and Maps, and then used the standard List and Map matchers. Much more flexible.