How to get Set of keys or values from Set of Map.Entry in scala? - scala

I have a set of Map.Entry like Set<Map.Entry<String, ConfigValue>> in scala. Now I want to get the Set either keys(String) or values(ConfigValue) in scala. Please suggest some easy solution for this problem.
Thanks

you can use .map to transform your Set[Map.Entry[String,ConfigValue]] to Set[String] and/or Set[ConfigValue]. however note that you might want to convert to List before to avoid collapsing duplicates.

So if you have
val map: Set[Map[K, V]] = ???
val keys = map.flatMap(_.keySet) will give you Set[K]
val values = map.flatMap(_.values) will give you Set[V]
In both cases duplicates will be removed.

You could create a couple of functions that describe that computation, like:
val getKeys: Set[JavaMap.Entry[String, ConfigValue]] => Set[String] = _.map(_.getKey)
val getValues: Set[JavaMap.Entry[String, ConfigValue]] => Set[ConfigValue] = _.map(_.getValue)
Then when you need to extract one or the other you can call them like so:
val setOfKeyMap: Set[Map.Entry[String, ConfigValue]] = ???
...
val setOfKeys: Set[String] = getKeys(setOfKeyMap)
val setOfValues: Set[ConfigValue] = getValues(setOfKeyMap)

Related

Extend / Replicate Scala collections syntax to create your own collection?

I want to build a map however I want to discard all keys with empty values as shown below:
#tailrec
def safeFiltersMap(
map: Map[String, String],
accumulator: Map[String,String] = Map.empty): Map[String, String] = {
if(map.isEmpty) return accumulator
val curr = map.head
val (key, value) = curr
safeFiltersMap(
map.tail,
if(value.nonEmpty) accumulator + (key->value)
else accumulator
)
}
Now this is fine however I need to use it like this:
val safeMap = safeFiltersMap(Map("a"->"b","c"->"d"))
whereas I want to use it like the way we instantiate a map:
val safeMap = safeFiltersMap("a"->"b","c"->"d")
What syntax can I follow to achieve this?
The -> syntax isn't a special syntax in Scala. It's actually just a fancy way of constructing a 2-tuple. So you can write your own functions that take 2-tuples as well. You don't need to define a new Map type. You just need a function that filters the existing one.
def safeFiltersMap(args: (String, String)*): Map[String, String] =
Map(args: _*).filter {
result => {
val (_, value) = result
value.nonEmpty
}
}
Then call using
safeFiltersMap("a"->"b","c"->"d")

How would I alter a list within a list in Scala using functional programming

Imagine I have a list[list[object]]
and I wanted to get a list[list[object.field]]
How would i be able to do this through functional programming
as in
if val list = list[list[object]]
i tried
val newList = list(_)(_1.map(object.field))
but this gave me an error and I am confused
I just started functional programming and scala so there might be something completely illogical with this statement
You need to use map as following
case class Obj(field: String)
val list = List[List[Obj]]()
val fields: List[List[String]] = list.map(_.map(_.field))
or same as
val fields: List[List[String]] = list.map(innerList => innerList.map(obj => obj.field))
or if you want to have a flattened list of fields
val fields: List[String] = list.flatMap(_.map(_.field))

split strings in array and convert to map

I am reading a file composed of lines in the format a=b.
Using Source.fromFile("file").getLines I get an Iterator[String]. I figure I need to split the strings into tuples and then form the map from the tuples - that is easy. I am not being able to go from the Iterator[String] to an Iterator[(String,String)].
How can I do this? I am a beginner to scala and not experienced with functional programming, so I am receptive to alternatives :)
You can do so by splitting the string and then creating the tuples from the first and second elements using Iterator.map:
val strings = List("a=b", "c=d", "e=f").iterator
val result: Iterator[(String, String)] = strings.map { s =>
val split = s.split("=")
(split(0), split(1))
}
If you don't mind the extra iteration and intermediate collection you can make this a little prettier:
val result: Iterator[(String, String)] =
strings
.map(_.split("="))
.map(arr => (arr(0), arr(1)))
You can transform the values returned by an Iterator using the map method:
def map[B](f: (A) ⇒ B): Iterator[B]
Maybe like this?
Source.fromFile("file").getLines.map(_.split("=").map( x => (x.head,x.tail) ) )
You might want to wrap this into Try.
This is my try:
val strings = List("a=b", "c=d", "e=f")
val map = strings.map(_.split("=")).map { case Array(f1,f2) => (f1,f2) }

Create Map in Scala using loop

I am trying to create a map after getting result for each items in the list. Here is what I tried so far:
val sourceList: List[(Int, Int)] = ....
val resultMap: Map[Int, Int] = for(srcItem <- sourceList) {
val result: Int = someFunction(srcItem._1)
Map(srcItem._1 -> result)
}
But I am getting type mismatch error in IntelliJ and I am definitely not writing proper syntax here. I don't think I can use yield as I don't want List of Map. What is correct way to create Map using for loop. Any suggestion?
The simplest way is to create the map out of a list of tuples:
val resultMap = sourceList.map(item => (item._1, someFunction(item._1))).toMap
Or, in the monadic way:
val listOfTuples = for {
(value, _) <- sourceList
} yield (value, someFunction(value))
val resultMap = listOfTuples.toMap
Alternatively, if you want to avoid the creation of listOfTuples you can make the transformation a lazy one by calling .view on sourceList and then call toMap:
val resultMap = sourceList.view
.map(item => (item._1, someFunction(item._1)))
.toMap
Finally, if you really want to avoid generating extra objects you can use a mutable Map instead and append the keys and values to it using += or .put

Can anyone 1-line this Scala code (preferably with FP?)

Sup y'all. The below feels like a tragic waste of Scala. Can anyone save this code?
val tokenSplit = token.split(":")(1)
val candidateEntityName = tokenSplit.substring(0,tokenSplit.length-1)
if(!candidateEntityName.equals(entityName)) removeEnd = true
Here it is (You don't need to use equals):
val removeEnd = token.split(":")(1).init != entityName
should be sth like: (untested)
val removeEnd = !(token.split(":")(1).dropRight(1).equals(entityName))
or:
val removeEnd = !(token.split(":").last.dropRight(1).equals(entityName))
A different solution using regex's to match on the input. It also handles the case where the data isn't as expected (you could of course extend your regex to suite your needs).
val removeEnd = """<(\w+):(\w+)>""".r.findFirstMatchIn(token).map(!_.group(2).equals(entityName)).getOrElse(throw new Exception(s"Can't parse input: $token"))
If you want to default to false:
val removeEnd = """<(\w+):(\w+)>""".r.findFirstMatchIn(token).exists(!_.group(2).equals(entityName))