Find the sum of a list in Scala - scala

If I have a list of strings and I know the numeric vlaue of each string in the list how do i get the sum of the list?
Example:
I know:
a = 1
b = 2
c = 3
d = 4
e = 5
I am given the following list:
List("a","b","d")
what the best way of calculating the sum 7?
Thanks

val a = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4, "e" -> 5)
val b = List("a", "b", "d")
b.map(a.getOrElse(_, 0)).sum

If you know that the values are the same as the element position, then you can avoid a map:
object test {
val list = List("a", "b", "c", "d", "e")
def sumThem = (for((letter, value) <- list.zipWithIndex) yield(value + 1)).sum
}
scala> test.sumThem
res2: Int = 15

If you're 100% sure it's only letters
List("a","b","d").foldLeft(0)(_ + _.hashCode - 96)
if not, you can map it before
val letters = (1 to 26).map(x => Character.toString((x+96).toChar) -> x).toMap
and use #sheunis's answer:
val input = List("a","b","d")
input.map(letters.getOrElse(_, 0)).sum

Related

Merging lists in scala

I have to merge these two lists together in a way that results in the 3rd list. I'm not super familiar with Scala that much but I am always interested in learning.
val variable = List("a", "b", "c") | val number = List("1", "2", "3")
When merged and printing each value after, it should result in an output like this
a is equal to 1
b is equal to 2
c is equal to 3
with a list that is now equal to
List("a is equal to 1", "b is equal to 2", "c is equal to 3")
Please help me out
zip and map would work,
variable.zip(number).map {case (str, int) => s"$str is equal to $int"}
Alternativly, you could use for-comprehensions
Welcome to Scala 3.1.1 (17, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
scala> val variable = List("a", "b", "c")
val variable: List[String] = List(a, b, c)
scala> val number = List("1", "2", "3")
val number: List[String] = List(1, 2, 3)
scala> for {
| str <- variable
| n <- number
| } yield s"$str is equal to $n"
val res0: List[String] = List(a is equal to 1, a is equal to 2, a is equal to 3, b is equal to 1, b is equal to 2, b is equal to 3, c is equal to 1, c is equal to 2, c is equal to 3)

How do I calculate the product of the occurrence of elements in 2 lists?

I have created a function that calculates the number of occurrences of element in a list, whereby if I pass the string
"d b d b d"
into the function, then it will return
(b -> 2, d -> 3)
Now what I want to do, is to create a new function that takes two arguments both List[String]
def foo(a: List[String], b: List[String]) : Int = {
}
And lets say I pass
List("a", "b", "b", "c", "d")
occurrences of this list = (a -> 1, b -> 2, c -> 1, d -> 1)
List("d", "b", "d", "b", "d")
occurrences of this list = (b -> 2, d -> 3)
into this function, it will calculate the occurrences of each element in each list, and then it calculates the product of each occurrence between the list. Therefore the expected answer from passing these two lists would be 7:
1*0 + 2*2 + 1*0 + 1*3 = 7
a b c d
How do I go about this?
You can do this:
def count(string: String): Map[String, Int] =
string.split(" ").groupBy(identity).mapValues(_.length)
def multiply(m1: Map[String, Int], m2: Map[String, Int]): Map[String, Int] = {
val allKeys = m1.keySet.union(m2.keySet)
allKeys.map(key => key -> m1.getOrElse(key, 0) * m2.getOrElse(key, 0)).toMap
}
val freq1 = count("a b b c d")
val freq2 = count("d b d b d")
val multiplied = multiply(freq1, freq2)
val sum = multiplied.values.sum

Scala - Undo a flatmap after transformation

How can I merge a Seq of Maps to a single Map i.e.
Seq[Map[String, String]] => Map[String, String]
For example:
val someSeq = rdd.map(_._2).flatMap(...) //some transformation to produce the sequence of maps
where someSeq is Seq(student1, student2) and student1 and student2 are Maps :
var student1 = Map(a -> "1", b -> "1")
var student2 = Map(c -> "1", d -> "1")
I need a result like this:
val apps = Map(a -> "1", b -> "1", c -> "1", d -> "1")
Any idea ?
Unrelated to Spark, but one approach would be to fold over the sequence as follows:
val student1 = Map("a" -> "1", "b" -> "1")
val student2 = Map("c" -> "1", "d" -> "1")
val students = Seq(student1, student2)
students.foldLeft(Map[String, String]())(_ ++ _)
Returns
Map(a -> 1, b -> 1, c -> 1, d -> 1)
In regards to "undoing" a flatMap, I don't believe this is really possible. In order to achieve that, consider the notion of undoing a "flatten".
For example:
val x = Seq(1, 2)
val y = Seq(3, 4)
val combined = Seq(x, y)
val flattened = combined.flatten
val b = Seq(1, 2, 3)
val c = Seq(4)
val combined2 = Seq(b, c)
val flattened2 = combined2.flatten
flattened == flattened2
Returns true.
So basically, in this instance, you can go from unflattened to flattened, but not vice versa, because vice versa would yield multiple answers.

Create Map holding a # of appearance for each List element [duplicate]

This question already has answers here:
Count occurrences of each element in a List[List[T]] in Scala
(3 answers)
Closed 9 years ago.
I'm new to Scala.
If I have the following List:
val ls = List("a", "a", "a", "b", "b", "c")
how can I create a Map that holds an number of appearances for every element in the list?
For example the Map for the list above should be:
Map("a" -> 3, "b" -> 2, "c" -> 1)
list.foldLeft(Map[String, Int]() withDefaultValue 0) { (m, x) => m + (x -> (m(x) + 1)) }
snippet in action:
scala> val list = List("a", "a", "b", "c", "c", "a")
list: List[String] = List(a, a, b, c, c, a)
scala> list.foldLeft(Map[String, Int]() withDefaultValue 0) { (m, x) => m + (x -> (1 + m(x))) }
res1: scala.collection.immutable.Map[String,Int] = Map(a -> 3, b -> 1, c -> 2)
(directly based on Count occurrences of each element in a List[List[T]] in Scala)
Not as efficient as Erik's foldLeft solution:
val ls = List("a", "a", "a", "b", "b", "c")
ls.groupBy(identity).mapValues(_.size)
res0: scala.collection.immutable.Map[String,Int] = Map(a -> 3, c -> 1, b -> 2)
With scalaz,
xs foldMap (x => Map(x -> 1))

Scala updating/creating value in a hashmap

I don't understand this with Scala hasmaps:
How do I create a value or update one if it does not exist?
I am tryng to count the number of characters in a list of Strings.
I've tried this code but it doesn't work :
def times(chars: List[Char]): List[(Char, Int)] = {
val map = new HashMap[Char, Int]()
chars.foreach(
(c : Char) => {
map.update(c, map.get(c) + 1)
})
}
I understand the returning type isn't correct.
But is my foreach loop wrong?
Is there a prettier way to write it?
I think this will answer your question:
scala> "abaccdba".groupBy(identity).mapValues(_.length)
res3: scala.collection.immutable.Map[Char,Int] = Map(b -> 2, d -> 1, a -> 3, c -> 2)
Oh, and btw HashMap has a method getOrElseUpdate as to your original question
If someone wonder how to use GetOrElseUpdate and find this post here is the exemple I found :
val map = Map('a' -> 1, 'b' -> 2) //> map :
scala.collection.immutable.Map[Char,Int] = Map(a -> 1, b -> 2)
val newval = map.getOrElse('b', 0) + 1 //> newval : Int = 3
val updated = map + ('b' -> (newval)) //> updated :
scala.collection.immutable.Map[Char,Int] = Map(a -> 1, b -> 3)