Gatling Feeder - get info from a list - scala

I want to create new Gatling feeder on a list[Strings] from the memory.
In the scenario, I am executing this:
**.feed(GetGroupIdFeeder.getGroupIdFeed)**
My feeder looks like that:
val getGroupIdFeed : Iterator[Map[String, List[String]]] = {
Iterator.continually(Map("groups" -> myList)) }
My list look like that: my_List["a" , "b" , "c"]
in results I am getting :
myList["a" , "b" , "c"] as expected from the feeder...
My expectations is to get from the feeder only "a"
I am aiming that my feeder will be configured as circular.
Details of what I want:
when calling the feeder:
On 1st call, I get "a"
on 2nd I get "b"
on 3rd "c" and
on 4th I get "a" again (circular)
How that can be done?
Any help in this regard would be helpful, thanks!

val getGroupIdFeed = Iterator.continually(List("a", "b", "c"))
.flatten
.map(value => Map("groups" -> value))

Related

Better way to create new key in map if key doesnt exist in Scala?

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.

How to find a map in list of maps where a key has a certain value in Scala?

I have a List[Map[String, Any] and I want to return the map which has a certain value for one of the keys. Here's an obfusticated example:
val items: List[Map[String, Any]] = List(Map("name" -> "A", "size" -> 50), Map("name" -> "B", "size" -> 75), Map("name" -> "C", "size" -> 100)))
val mapB: Map[String, Any] = items.find(|m| m("name") == "B") // Psuedo code
mapB would be Map("name" -> "B", "size" -> 75).
Bonus Question
Is there also a way to return the value of another key instead of the whole Map?
For example, if I only wanted the size value (75) for name B? I know I can extract it from the Map as a two-step operation, but if there's another more idiomatic way, I'd be interested in learning it.
Thanks!
find() returns an Option in case what you're looking for cannot be found.
val mapB: Option[Map[String, Any]] = items.find(_("name") == "B") //safe
or
val mapB: Map[String, Any] = items.find(_("name") == "B").get //unsafe, might throw
To retrieve the size value from the first Map where "name" -> "B" you could do something like this.
val sz :Any = items.find(m => m.get("name").contains("B")
&& m.get("size").nonEmpty).fold(0:Any)(_("size"))
Note that sz is type Any because that's what the type of the Map values. Which means that you'd have to cast it (discouraged) to type Int before you can do anything useful with it.
Avoid type Any. It's a sure sign that you're going in the wrong direction.
Complementing jwvh's answers (and using Tim's suggestion to improve safety).
Here is a function that addresses your bonus question.
def findAndGet(maps: List[Map[String, Any]], condition: (String, Any), key: String): Option[Any] = condition match {
case (k, v) =>
maps.find(map => map.get(k).contains(v)).flatMap(map => map.get(key))
}
findAndGet(maps = items, condition = ("name", "B"), key = "size")
// res0: Option[Any] = Some(75)
BTW, a Map[String, Any] makes me thing you are dealing with JSONs, have you take a look to any of the Scala libraries for dealing with them in a more "typesafe" way?, having an Any in your code should always be an alarm that something is wrong.

Append auto-incrementing suffix to duplicated elements of a List

Given the following list :
val l = List("A", "A", "C", "C", "B", "C")
How can I add an auto-incrementing suffix to every elements so that I end up with a list containing no more duplicates, like the following (the ordering doesn't matter) :
List("A0", "A1", "C0", "C1", "C2", "B0")
I found it out by myself just after having written this question
val l = List("A", "A", "C", "C", "B", "C")
l.groupBy(identity) // Map(A->List(A,A),C->List(C,C,C),B->List(B))
.values.flatMap(_.zipWithIndex) // List((A,0),(A,1),(C,0),(C,1),(C,2),(B,0))
.map{ case (str, i) => s"$str$i"}
If there is a better solution (using foldLeft maybe) please let me know
In a single pass straightforward way :
def transformList(list : List[String]) : List[String] = {
val buf: mutable.Map[String, Int] = mutable.Map.empty
list.map {
x => {
val i = buf.getOrElseUpdate(x, 0)
val result = s"${x.toString}$i"
buf.put(x, i + 1)
result
}
}
}
transformList( List("A", "A", "C", "C", "B", "C"))
Perhaps not the most readable solution, but...
def appendCount(l: List[String]): List[String] = {
// Since we're doing zero-based counting, we need to use `getOrElse(e, -1) + 1`
// to indicate a first-time element count as 0.
val counts =
l.foldLeft(Map[String, Int]())((acc, e) =>
acc + (e -> (acc.getOrElse(e, -1) + 1))
)
val (appendedList, _) =
l.foldRight(List[String](), counts){ case (e, (li, m)) =>
// Prepend the element with its count to the accumulated list.
// Decrement that element's count within the map of element counts
(s"$e${m(e)}" :: li, m + (e -> (m(e) - 1)))
}
appendedList
}
The idea here is that you create a count of each element in the list. You then iterate from the back of the list of original values and append the count to the value while decrementing the count map.
You need to define a helper here because foldRight will require both the new List[String] and the counts as an accumulator (and, as such, will return both). You'll just ignore the counts at the end (they'll all be -1 anyway).
I'd say your way is probably more clear. You'll need to benchmark to see which is faster if that's a concern.
Ideone.

Scala Collections: Using a value of Set find the key from a Map object.

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

Scala dynamic tuple type construction from sequence

I'm trying to generate some json using the json4s library which builds json using a dsl based around nested tuple structures. I have a scala Seq that I'd like to be able to convert to a nesting of tuples like so:
// scala Seq
val s = Seq("a", "b", "c", "d")
val rootItem = "id" -> 1234
// desired json
{
"a" : {
"b" : {
"c" : {
"d" : {
"id" : 1234
}
}
}
}
}
If I force it to ignore the types I can produce the desired tuple structure as follows:
// yields ("a", ("b", ("c", ("d", ("id", 1234)))))
s.foldRight[Any](rootItem)(_ -> _)
but because the type of the result is now denoted as Any the implicit conversion that write this to json don't fire (and throw an exception when called explicitly) despite the actual type being correct. I'm at a loss for how to construct this datastructure in a typesafe way. Ideally I'd like a solution that is able to appropriately build up the type, though I understand that it might be impossible since it requires information only available at runtime (the length of the list). I know that scala supports recursive types, which seem to potentially fit the bill but I haven't been able to understand how to work them in this case and don't know if they are safe for a 'real' system.
You're not going to be able to do this with a plain old fold, since the accumulator has to be the same type the whole time.
You can make the transformation to JSON as you go, however:
val s = Seq("a", "b", "c", "d")
val rootItem = "id" -> 1234
import org.json4s._
import org.json4s.JsonDSL._
import org.json4s.jackson.JsonMethods._
val json = s.foldRight[JObject](rootItem)(_ -> _)
And then you can do the following, since json is statically typed as a JObject:
scala> pretty(render(json))
res0: String =
{
"a" : {
"b" : {
"c" : {
"d" : {
"id" : 1234
}
}
}
}
}
(As a footnote, there is a way you could do the fold with tuples and end up with the appropriate static type, but that's almost certainly not what you want in this case.)