I have a ListBuffer of Maps in scala. All maps inside the buffer contain some keys. For example:
ListBuffer(
Map(
"date" -> 24092018,
"datetime" -> "24-09-2018 11:23:44",
"lat" -> "48.33"
),Map(
"date" -> 24092018,
"datetime" -> "24-09-2018 11:53:44",
"lat" -> "48.33"
),Map(
"date" -> 23092018,
"datetime" -> "23-09-2018 10:53:44",
"lat" -> "48.33"
)
)
I want to sort this ListBuffer based on datetime so that latest one will come first.
sortBy is a method of the object (and reverse too); Directly from the language reference:
def sortBy[B](f: (A) ⇒ B)(implicit ord: math.Ordering[B]): ListBuffer[A]
Sorts this Seq according to the Ordering which results from transforming an implicitly given Ordering with a transformation function.
Related
My list of Maps is like below
val myMap= List(
Map("name" -> "1st" , "status" -> "0"),
Map("name" -> "2nd" , "status" -> "1"),
Map("name" -> "3rd" , "status" -> "1")
)
I am trying to filter the list based on "status" = "1" and get another List of Maps with only name
So the output should be
Map("name" -> "2nd"),
Map("name" -> "3rd")
I am a beginner in scala, understand that I need to apply map,filter. But not getting how to proceed here.
If you are doing both filter and map the best solution is often to use collect:
myMap.collect{ case m if m.get("status").contains("1") => m - "status" }
Consider combining filter & map into collect:
val myMap = List(
Map("name" -> "1st", "status" -> "0"),
Map("name" -> "2nd", "status" -> "1"),
Map("name" -> "3rd", "status" -> "1"),
Map("xx" -> "4th", "status" -> "1"),
Map("name" -> "5th", "yy" -> "1")
)
myMap.collect{ case m if m.get("status").contains("1") && m.get("name").nonEmpty =>
Map("name" -> m("name"))
}
// List(Map(name -> 2nd), Map(name -> 3rd))
The guard clause in collect ensures that only those Maps consisting of key-value status->1 as well as key name will be included.
With filter and map you can write is as follows
myMap
.filter(m => m.get("status") == Some("1")) // filter maps with status 1
.map(m => "name" -> m.get("name").get) // use the name attribute to create a new map
Note that the get method returns an Option since the requested key might not exist. Therefore you need to compare with Some("1") and also use the .get on the result of m.get("name"). Using the .get method without checking that the option is not empty is not a good style, since this will fail at runtime if the map doesn't contain a name key.
A better approach which would omit these maps from the result could be
myMap
.filter(m => m.get("status") == Some("1"))
.flatMap(m => m.get("name").map(n => "name" -> n))
The map used here is from the Option class and will map a found name to Some("name" -> n) and None to None. The flatMap will finally unpack the Some and ignore the None elments
I have the following list of maps in Scala:
val list = List(Map( "age" -> 25, "city" -> "London", "last_name" -> "Smith"),
Map("city" -> "Berlin", "last_name" -> "Robinson"))
And I wish to iterate through the list of maps and check if the key "age" exists. If it doesnt, I want to create the entry and put it in the map. So far I have tried:
val tmp = list.map( item => if (!item.contains("age")) item.updated("age",5) else item)
print(tmp)
which works fine, I just wanted to know if there is a more efficient way to do it (perhaps with comprehensions or anything else?)! Any advice would be appriciated
I'd do it this way.
val newList =
list.map{m => if (m.keySet("age")) m else m + ("age" -> "5")}
Note that if you don't make the value 5 a String then the result is a Map[String,Any], which is not what you want.
This is a scala question.
I currently have the following two collections objects:
val keywordLookup = Map("a" -> "1111",
"b" -> "2222",
"c" -> "3333",
"d" -> "4444",
"e" -> "5555")
val keywordList = Set("1111", "3333")
The keywordLookup is a lookup object. The keywordList contains a list of values that I need to find the Ids from the keywordLookup object.
I would like the get the following result:
Map("a" -> "1111", "c" -> "3333")
val filtered = keywordLookup.filter(kv => keywordList.contains(kv._2))
filtered is the Map you want as output
keywordLookup.filter(x => keywordList.contains(x._2))
Using flatMap on find,
keywordList.flatMap (k => keywordLookup.find( _._2 == k)).toMap
I have a nested map Data Structure of the following type:
SortedMap[Time: Long,SortedMap[Name: String, Value: Double]]
"Time" elements are of type Long and indicate the timestamp of the data.
"Name" elements are of type String and indicate the name of the element.
"Value" elements are of type Double and indicate the elements value for timestamp "Time".
The basic idea is that for each timestamp, we have several elements, each has a specific value for the current timestamp.
The result i want is an Array[Double] or List[Double] for each "Name" element. I don't need the "Time" value except i want the result to be ordered in the same way.
Example:
val dataType = SortedMap(1000L -> SortedMap("component1" -> 1.0,
"component2" -> 1.1), 2000L -> SortedMap("component1" -> 1.1),
3000L -> SortedMap("component1" -> 0.95))
The result i want is the following:
"component1" - 1.0, 1.1, 0.95
"component2" - 1.1
Can anyone please help?
I think the result-type you want is a Map[String, Seq[Double]. I will use a Vector for the sorted values, because it has an efficient append method :+.
First, you want to drop the time-keys of the outer map. You can use values or valuesIterator for that. Then perhaps the easiest is to perform a "fold-left" over these values, starting with an empty result map and updating it at each step. You need two nested folds, because you iterate first over the maps and then over the individual elements of each map.
import scala.collection.immutable.SortedMap
val dataType = SortedMap(
1000L -> SortedMap("component1" -> 1.0, "component2" -> 1.1),
2000L -> SortedMap("component1" -> 1.1),
3000L -> SortedMap("component1" -> 0.95)
)
(Map.empty[String, Vector[Double]] /: dataType.values) { case (res0, map) =>
(res0 /: map) { case (res1, (key, value)) =>
res1.updated(key, res1.getOrElse(key, Vector.empty) :+ value)
}
}
// Map(component1 -> Vector(1.0, 1.1, 0.95), component2 -> Vector(1.1))
Note the fold-left call (init /: coll) …. You can use the alternative method coll.foldLeft(init) … which yields slightly different syntax:
dataType.values.foldLeft(Map.empty[String, Vector[Double]]) { case (res0, map) …
You can swap Map for SortedMap in the result if you want the component names to remain sorted.
Practicing what is written here: ScalaForms, I have created the following form:
val personCreationForm = Form(
tuple (
"name" -> nonEmptyText,
"age" -> number verifying (min(0), max(100)) /*ERROR*/
) verifying ("Wrong entry", result => result match {
case (name, age) => true
})
)
However, the error on verifying states that value verifying is not a member of (java.lang.String, play.api.data.Mapping[Int]).
Working with mapping instead of tuple, as in the referenced example, makes no difference. What is wrong here?
According to Scala operators precedence rules, methods starting with a letter have a lower precedence than others so when you write:
"age" -> number verifying (min(0), max(100))
The compiler builds the following expression:
("age" -> number) verifying (min(0), max(100))
Which is not what you want! You can rewrite it as follows:
"age" -> number.verifying(min(0), max(100))
"age" -> (number verifying (min(0), max(100)))
And the current Play documentation is wrong. Thanks for catching it!