scala build a dictionary from a list and a function - list

I have a scala list and a funcion:
val l = List((1,2), (3,4), (5,6))
def f(x:Int, y:Int) = x+y
I want to build a dictionary that associated to each tuple its sum.
The result f(1,2) should be kept in memory and not recomputed each time that it is called. How can I do that? In python I would use a dictionary.

l.map(x => x -> (f _).tupled(x)).toMap

An analog to Python dictionaries in Scala is Map:
λ val resultsMap = Map( // Create a map from a Seq of (key, value) pairs
l.zip( // List(((1, 2), SOMETHING), ((3, 4), SOMETHING), etc.)
l.map((f _).tupled) // Invoke `f` on each entry in `l`
).toSeq : _*)
resultsMap: Map[(Int, Int), Int] = Map((1, 2) -> 3, (3, 4) -> 7, (5, 6) -> 11)
Usage:
λ resultsMap((1, 2))
res0: Int = 3

Using a for comprehension we can extract the tuple values as well as bind each tuple for constructing the associations, like this,
for ( t#(a,b) <- l ) yield t -> f(a,b)
Thus applying toMap on the collection from the comprehension we get the desired map. In this approach though we must declare as many items in the tuple as we wish to be applied to the function.

Related

SML adding indices to a list

Given a generic list, return a list containing the same objects in a tuple with their index in the list.
For example:
f ["a", "b"];
- val it = [(0,"a") , (1,"b")] : (int * string) list
The function should be a one-liner, meaning no pattern matching, recursion, if/else, helper functions and let/local. So far i could only make a list of indices given the input list:
fun f lst = List.take((foldl (fn (x,list) => [(hd(list)-1)]#list) [length(lst)] (lst)),length(lst));
f [#"a",#"b"];
- val it = [0, 1]: int List.list;
I should add the list items to these indices in a tuple but i'm not sure how to do that.
Here is a hint for one way to solve it:
1) Using List.sub, create an anonymous function which sends an index i to the pair consisting of i and the lst element at index i.
2) Map this over the result obtained by calling List.tabulate on length lst and the function which sends x to x.
I was able to get this to work (on one line), but the result is ugly compared to a straightforward pattern-matching approach. Other than as a puzzle, I don't see the motivation for disallowing that which makes SML an elegant language.
It appears that i forgot the #i operator to access the i'th element of a tuple. The answer is the following:
fun f xs = List.take((foldr (fn (x,list) => [(#1(hd(list))-1,x)]#list) [(length(xs),hd(xs))] (xs)),length(xs));
f (explode "Hello");
- val it = [(0, #"H"), (1, #"e"), (2, #"l"), (3, #"l"), (4, #"o")]: (int * char) List.list;

Scala Summing Values of a list of Tuples in style (String,Int) based on _._1

I create a list of tuples via taking a String name and matching it to an accompanying int value.
I want to be able to sum those int values in the tuple in the case that there are multiple strings of the same name. My current approach follows this utilization of groupby which if I understand right is returning me a Map with keys based upon _ . _ 1 and list of values:
def mostPopular(data: List[List[String]]): (String, Int) = {
//take the data and create a list[(String,Int)]
val nameSums = data.map(x => x(1) -> x(2).toInt)
//sum the values in _._2 based on same elements in _._1
val grouped = nameSums.groupBy(_._1).foldLeft(0)(_+_._2)
}
I've seen other solution that have dealt with averaging different values of tuples but they haven't explained how to sum values that fall under the same name
In your case value (see below code snippet) is a list of (String, Int) do value.map(_._2).sum or value.foldLeft(0)((r, c) => r + (c._2))
nameSums.groupBy(_._1).map { case (key, value) => key -> (value.map(_._2)).sum}
Scala REPL
scala> val nameSums = List(("apple", 10), ("ball", 20), ("apple", 20), ("cat", 100))
nameSums: List[(String, Int)] = List((apple,10), (ball,20), (apple,20), (cat,100))
scala> nameSums.groupBy(_._1).map { case (key, value) => key -> (value.map(_._2)).sum}
res15: scala.collection.immutable.Map[String,Int] = Map(cat -> 100, apple -> 30, ball -> 20)

Scala list of list count different elements per sublist index

I have a list of lists with the following data
val list = List(List("a","b","c"),List("d","e","f"),List("a","a","a"))
I want to disicover how many different data do I have in each position of the sublists
1 -> List("a","d","a")
2 -> List("b","e","a")
3 -> List("c","f","a")
Is there a way to do that? It doesn't need to be indexed, but I need the amount of different values per sublist index, the result could also be
2 // different values a and d
3 // different values b, e and a
3 // different values c, f and a
As I noted in a comment on Jhonny Everson's (almost right but now deleted) answer, you can use transpose to get a list of the columns, and then distinct to remove duplicates:
scala> list.transpose.map(_.distinct.size)
res0: List[Int] = List(2, 3, 3)
This will throw an exception if all the lists don't have the same size, but that's probably what you want.
scala> list.transpose.map(_.toSet.size)
res0: List[Int] = List(2, 3, 3)
The output of list.transpose is List(List(a, d, a), List(b, e, a), List(c, f, a)) which gives you the structure you want then map each List to a Set to get the unique elements and count them.
If you want unique elements per position, then you can use zipWithIndex and reverse the outputs.
scala> list.transpose.map(_.distinct).zipWithIndex.map(t => t._2 -> t._1)
res1: List[(Int, List[String])] = List((0,List(a, d)), (1,List(b, e, a)), (2,List(c, f, a)))
Here is the code you wanted:
var lOfl = List(List.range(1,5), List(2,2,2,3), Nil)
//> lOfl : List[List[Int]] = List(List(1, 2, 3, 4), List(2, 2, 2, 3), List())
for {
l <- lOfl
} yield l.toSet.count(_ => true) //> res1: List[Int] = List(4, 2, 0)
A sample list of list of Int is created as lOfl; for loop iterates through each list of Int; toSet converts list to set eliminating duplicate elements. then count function does as the name says it all.
OR use the Scala's most used collection function (:P :P), map, like below,
lOfl.map(l => l.toSet.count(_ => true) ) //> res2: List[Int] = List(4, 2, 0)

How to convert integer list to map removing duplicates?

Let's say that I have a Map of strings -> List of Integers. I would like to create a function which takes in as a parameter a List of strings and returns all the integers correlating to all the string in that list. I.e. if the Map X contains the following mappings:
database = [("Bob",[1,2,3]),("John",[1,5,6]),("Trevor",[4,5,7])]
If this function takes in ["Bob","John"] as the list of names, it should return,
[1,2,3,5,6]
Since Bob correlates to 1,2,3 and John correlates to 1,5,6 (same entries for both names aren't duplicated). I also would like to not introduce a mutable variable if I don't have to, thus leading me to believe a for comprehension that yields this list of number values would be the best way to achieve this, but I'm not sure how.
If you want to use a for-comprehension you can so this:
val result = for {
key <- keys
nums <- map.get(key).toSeq
num <- nums
} yield num
result.distinct
Explanation:
for each key in the list try to get an entry and convert it to a Seq (necessary because flatMap expects a Seq in this case) and add every number in the list to the result. If the key is not present in the map the collection will be empty and therefore not yield any results. At the end call distinct to remove the duplicates.
val myMap = Map("Bob" -> List(1,2,3), "John" -> List(1,5,6), "Trevor" -> List(4,5,7))
val names = List("Bob", "John")
You can add default value to Map using method withDefaultValue:
val mapWithDefaul = myMap withDefaultValue Nil
Then you could use Map as function in flatMap:
names.flatMap(mapWithDefaul).distinct
// List(1, 2, 3, 5, 6)
Let
val db = Map("Bob" -> List(1,2,3), "John" -> List(1,5,6), "Trevor" -> List(4,5,7))
val names = List("Bob", "John")
Then a similar approach to #senia's using flatMap,
implicit class mapCorr[A,B](val db: Map[A,List[B]]) extends AnyVal {
def corr(keys: List[A]): List[B] = {
keys.flatMap{ k => db get k }.flatten.distinct
}
}
and
scala> db.corr(keys)
res0: List[Int] = List(1, 2, 3, 5, 6)
Here we allow for key lists of type A and maps from type A to type List[B] .
val myset = Set("Bob","John")
val database = Map(("Bob"->List(1,2,3)),("John"->List(1,5,6)),("Trevor"->List(4,5,7)))
val ids = database.filter(m => myset.contains(m._1)).map(_._2).flatten.toList.distinct
outputs:
ids: List[Int] = List(1, 2, 3, 5, 6)
Something like:
val result = database.filter(elem => list.contains(elem._1)).foldLeft(List())((res,elem) => res ++ elem._2)
where list is the input list of names.

How to convert a List(List[String]) into a Map[String, Int]?

I have a List(List("aba, 4"), List("baa, 2"))and I want to convert it into a map:
val map : Map[String, Int] = Map("aba" -> 4, "baa" -> 2)
What's the best way to archive this?
UPDATE:
I do a database query to retrieve the data:
val (_, myData) = DB.runQuery(...)
This returns a Pair but I'm only interested in the second part, which gives me:
myData: List[List[String]] = List(List(Hello, 19), List(World, 14), List(Foo, 13), List(Bar, 13), List(Bar, 12), List(Baz, 12), List(Baz, 11), ...)
scala> val pat = """\((.*),\s*(.*)\)""".r
pat: scala.util.matching.Regex = \((.*),\s*(.*)\)
scala> list.flatten.map{case pat(k, v) => k -> v.toInt }.toMap
res1: scala.collection.immutable.Map[String,Int] = Map(aba -> 4, baa -> 2)
Yet another take:
List(List("aba, 4"), List("baa, 2")).
flatten.par.collect(
_.split(",").toList match {
case k :: v :: Nil => (k, v.trim.toInt)
}).toMap
Differences to the other answers:
uses .par to parallelize the creation of the pairs, which allows us to profit from multiple cores.
uses collect with a PartialFunction to ignore strings that are not of the form "key, value"
Edit: .par does not destroy the order as the answer state previously. There is only no guarantee for the execution order of the list processing, so the functions should be side-effect free (or side-effects shouldn't care about the ordering).
My take:
List(List("aba, 4"), List("baa, 2")) map {_.head} map {itemList => itemList split ",\\s*"} map {itemArr => (itemArr(0), itemArr(1).toInt)} toMap
In steps:
List(List("aba, 4"), List("baa, 2")).
map(_.head). //List("aba, 4", "baa, 2")
map(itemList => itemList split ",\\s*"). //List(Array("aba", "4"), Array("baa", "2"))
map(itemArr => (itemArr(0), itemArr(1).toInt)). //List(("aba", 4), ("baa", 2))
toMap //Map("aba" -> 4, "baa" -> 2)
Your input data structure is a bit awkward so I don't think you can optimize it/shorten it any further.
List(List("aba, 4"), List("baa, 2")).
flatten. //get rid of those weird inner Lists
map {s=>
//split into key and value
//Array extractor guarantees we get exactly 2 matches
val Array(k,v) = s.split(",");
//make a tuple out of the splits
(k, v.trim.toInt)}.
toMap // turns an collection of tuples into a map