Scala Map And Pair Manipulation - scala

I am a beginner in Scala. I read this code about Map manipulation but can't understand how it works.
val terms = Map (1 -> 1.0, 2-> 2.0)
val (exp, coeff) = (2, 4.0)
exp -> (coeff + terms(exp)) //> res: (Int, Double) = (2,6.0)
coeff + terms(exp) //> res: Double = 6.0
I think the third line probably applied a map function,
but the right hand side is apparently a number.
Why the output is a pair?
Thanks.

val (exp, coeff) = (2, 4.0)
This is a deconstructor, it assigns the values 2 and 4.0 to the names exp and coeff. exp is now 2 and coeff is now 4.0.
terms(exp)
This is a map-lookup which results in 2.0
exp -> (coeff + terms(exp))
This arrow -> is a short hand term for constructing a Pair. It now has the values 2 and 6.0 because coeff + terms(exp) is 6.0.

terms(exp) accesses the value of the "map object" terms at the key defined by exp.
In contrast to this, the usage of a "map method" would look like this:
val list = List(1, 2, 3, 4)
val double = (i: Int) => i * 2
val list2 = list.map(double)
printf(list2.toString)
list.map(double) executes the function literal double for every member of the list and gives back a new List object.
The printed output is:
List(2, 4, 6, 8)

terms(exp) is a map lookup, resolving to 2.0
(coeff + terms(exp)) is, therefore 4.0 + 2.0
In exp -> (coeff + terms(exp)) the arrow -> constructs a pair of the left and right operands.

Related

Scala Map collection and map method

I don't understand why def + and def adjust of the following Scala code can be correct. I understand def adjust is used to adjust coefficients because when p1 and p2 have same exponents, their respective coefficients need to be summed up together when summing p1 and p2. But what I dont' understand is that: 1) This should be taken care of by code "other.terms map adjust)" under def + ; 2) and if 1)is correct, “terms ++ " in the same def will add p1's coefficient one more time, which should be wrong.
I'm confused as this code works well. Can someone please help me? Thanks a lot!
object polynomials {
class Poly(terms0: Map[Int, Double]) {
val terms = terms0 withDefaultValue 0.0
def +(other: Poly) = new Poly(terms ++ (other.terms map adjust))
def adjust(term: (Int, Double)): (Int, Double) = {
val (exp, coeff) = term
exp -> (coeff + terms(exp))
}
override def toString =
(for ((exp, coeff) <- terms.tolist.sorted.reverse) yield coeff + ”x^” + exp) mkString “+”
}
val p1 = new Poly(Map(1 -> 2.0, 3 -> 4.0, 5 -> 6,2))
val p2 = new Poly(Map(0 -> 3.0, 3 -> 7.0)
p1 + p2
Quick answers:
other.terms map adjust only includes terms from other, but there may be terms in this that are not in other. In order to retain those terms, the adjusted terms are added to the existing ones.
++ on two maps does not merge values with the same key, it replaces any values from the left-hand Map with those from the right-hand Map with the same key. So the terms from other.terms map adjust will replace those in this.terms not modify them.

How to pair each element of a Seq with the rest?

I'm looking for an elegant way to combine every element of a Seq with the rest for a large collection.
Example: Seq(1,2,3).someMethod should produce something like
Iterator(
(1,Seq(2,3)),
(2,Seq(1,3)),
(3,Seq(1,2))
)
Order of elements doesn't matter. It doesn't have to be a tuple, a Seq(Seq(1),Seq(2,3)) is also acceptable (although kinda ugly).
Note the emphasis on large collection (which is why my example shows an Iterator).
Also note that this is not combinations.
Ideas?
Edit:
In my use case, the numbers are expected to be unique. If a solution can eliminate the dupes, that's fine, but not at additional cost. Otherwise, dupes are acceptable.
Edit 2: In the end, I went with a nested for-loop, and skipped the case when i == j. No new collections were created. I upvoted the solutions that were correct and simple ("simplicity is the ultimate sophistication" - Leonardo da Vinci), but even the best ones are quadratic just by the nature of the problem, and some create intermediate collections by usage of ++ that I wanted to avoid because the collection I'm dealing with has close to 50000 elements, 2.5 billion when quadratic.
The following code has constant runtime (it does everything lazily), but accessing every element of the resulting collections has constant overhead (when accessing each element, an index shift must be computed every time):
def faceMap(i: Int)(j: Int) = if (j < i) j else j + 1
def facets[A](simplex: Vector[A]): Seq[(A, Seq[A])] = {
val n = simplex.size
(0 until n).view.map { i => (
simplex(i),
(0 until n - 1).view.map(j => simplex(faceMap(i)(j)))
)}
}
Example:
println("Example: facets of a 3-dimensional simplex")
for ((i, v) <- facets((0 to 3).toVector)) {
println(i + " -> " + v.mkString("[", ",", "]"))
}
Output:
Example: facets of a 3-dimensional simplex
0 -> [1,2,3]
1 -> [0,2,3]
2 -> [0,1,3]
3 -> [0,1,2]
This code expresses everything in terms of simplices, because "omitting one index" corresponds exactly to the face maps for a combinatorially described simplex. To further illustrate the idea, here is what the faceMap does:
println("Example: how `faceMap(3)` shifts indices")
for (i <- 0 to 5) {
println(i + " -> " + faceMap(3)(i))
}
gives:
Example: how `faceMap(3)` shifts indices
0 -> 0
1 -> 1
2 -> 2
3 -> 4
4 -> 5
5 -> 6
The facets method uses the faceMaps to create a lazy view of the original collection that omits one element by shifting the indices by one starting from the index of the omitted element.
If I understand what you want correctly, in terms of handling duplicate values (i.e., duplicate values are to be preserved), here's something that should work. Given the following input:
import scala.util.Random
val nums = Vector.fill(20)(Random.nextInt)
This should get you what you need:
for (i <- Iterator.from(0).take(nums.size)) yield {
nums(i) -> (nums.take(i) ++ nums.drop(i + 1))
}
On the other hand, if you want to remove dups, I'd convert to Sets:
val numsSet = nums.toSet
for (num <- nums) yield {
num -> (numsSet - num)
}
seq.iterator.map { case x => x -> seq.filter(_ != x) }
This is quadratic, but I don't think there is very much you can do about that, because in the end of the day, creating a collection is linear, and you are going to need N of them.
import scala.annotation.tailrec
def prems(s : Seq[Int]):Map[Int,Seq[Int]]={
#tailrec
def p(prev: Seq[Int],s :Seq[Int],res:Map[Int,Seq[Int]]):Map[Int,Seq[Int]] = s match {
case x::Nil => res+(x->prev)
case x::xs=> p(x +: prev,xs, res+(x ->(prev++xs)))
}
p(Seq.empty[Int],s,Map.empty[Int,Seq[Int]])
}
prems(Seq(1,2,3,4))
res0: Map[Int,Seq[Int]] = Map(1 -> List(2, 3, 4), 2 -> List(1, 3, 4), 3 -> List(2, 1, 4),4 -> List(3, 2, 1))
I think you are looking for permutations. You can map the resulting lists into the structure you are looking for:
Seq(1,2,3).permutations.map(p => (p.head, p.tail)).toList
res49: List[(Int, Seq[Int])] = List((1,List(2, 3)), (1,List(3, 2)), (2,List(1, 3)), (2,List(3, 1)), (3,List(1, 2)), (3,List(2, 1)))
Note that the final toList call is only there to trigger the evaluation of the expressions; otherwise, the result is an iterator as you asked for.
In order to get rid of the duplicate heads, toMap seems like the most straight-forward approach:
Seq(1,2,3).permutations.map(p => (p.head, p.tail)).toMap
res50: scala.collection.immutable.Map[Int,Seq[Int]] = Map(1 -> List(3, 2), 2 -> List(3, 1), 3 -> List(2, 1))

Scala - List to List of tuples

Beginner here.
Sorry but I did'nt found an answer so I ask the question here.
I want to know how to do this by using the Scala API :
(blabla))( -> List(('(',2),(')',2))
Currently I have this :
"(blabla))(".toCharArray.toList.filter(p => (p == '(' || p == ')')).sortBy(x => x)
Output :
List((, (, ), ))
Now how can I map each character to the tuples I describe ?
Example for a general case :
"t:e:s:t" -> List(('t',2),('e',1),('s',1),(':',3))
Thanks
val source = "ok:ok:k::"
val chars = source.toList
val shorter = chars.distinct.map( c => (c, chars.count(_ == c)))
//> shorter : List[(Char, Int)] = List((o,2), (k,3), (:,4))
Classic groupBy . mapValues use case:
scala> val str = "ok:ok:k::"
str: String = ok:ok:k::
scala> str.groupBy(identity).mapValues(_.size) // identity <=> (x => x)
res0: scala.collection.immutable.Map[Char,Int] = Map(k -> 3, : -> 4, o -> 2)
I like sschaef's solution very much, but I was wondering if anyone could weigh in on how efficient that solution is compared to this one:
scala> val str = "ok:ok:k::"
str: String = ok:ok:k::
scala> str.foldLeft(Map[Char,Int]().withDefaultValue(0))((current, c) => current.updated(c, current(c) + 1))
res29: scala.collection.immutable.Map[Char,Int] = Map(o -> 2, k -> 3, : -> 4)
I think my solution is slower. If we have n total occurrences and m unique values:
My solution: we have the fold left over all occurrences or n. For each of these occurrences we look up once to find the current count and then again to create the updated the map. I'm assuming that the creating of the updated map is constant time.
Total complexity: n * 2m or O(n*m)
sschaef's solution: we have the groupBy which I'm assuming just adds entries onto a list without checking the map (so for all values this would be a constant time look up plus appending to the list) so n. Then for the mapValues it probably iterates over the unique values and grabs the size for each key's list. I'm assuming that getting the size of each entry's list is constant time.
Total complexity: O(n + m)
Does this seem correct or am I mistaken in my assumptions?

Adding value to Scala map

Why does this work:
val x = Map[Int,Int]()
val y = (1, 0)
x + y
but not this?
val x = Map[Int,Int]()
x + (1, 0)
The error produced is:
<console>:11: error: type mismatch;
found : Int(1)
required: (Int, ?)
x + (1,0)
^
If I were to enter (1,0) into the REPL, it correctly types it as (Int,Int).
I should add that this works fine:
x + (1 -> 0)
This is an ambiguity caused by the similarity between the notation for tuples and the one for parameter lists :
x + (1,0) is notation for x.+(1,0) but sadly there is no method on x that takes two Int parameters. What you want is x.+((1,0)), i.e. x + ((1,0)).
There is something in Scala called auto-tupling, see this question and answers, which rewrites, for example, println (1,2) to println((1,2)). Except this will not work here because the + method takes a variable number of arguments and not a single one like println.
You get that strange error message because it expect every value in your parameter list (1,0) to be a tuple, as in myMap + ((1,2), (1,3), (3,4)). It finds an Int instead of a (Int, Int), hence the error.
add another pair of parentheses to make it work:
val x = Map[Int,Int]()
x + ((1, 0))

Count occurrences of each element in a List[List[T]] in Scala

Suppose you have
val docs = List(List("one", "two"), List("two", "three"))
where e.g. List("one", "two") represents a document containing terms "one" and "two", and you want to build a map with the document frequency for every term, i.e. in this case
Map("one" -> 1, "two" -> 2, "three" -> 1)
How would you do that in Scala? (And in an efficient way, assuming a much larger dataset.)
My first Java-like thought is to use a mutable map:
val freqs = mutable.Map.empty[String,Int]
for (doc <- docs)
for (term <- doc)
freqs(term) = freqs.getOrElse(term, 0) + 1
which works well enough but I'm wondering how you could do that in a more "functional" way, without resorting to a mutable map?
Try this:
scala> docs.flatten.groupBy(identity).mapValues(_.size)
res0: Map[String,Int] = Map(one -> 1, two -> 2, three -> 1)
If you are going to be accessing the counts many times, then you should avoid mapValues since it is "lazy" and, thus, would recompute the size on every access. This version gives you the same result but won't require the recomputations:
docs.flatten.groupBy(identity).map(x => (x._1, x._2.size))
The identity function just means x => x.
docs.flatten.foldLeft(new Map.WithDefault(Map[String,Int](),Function.const(0))){
(m,x) => m + (x -> (1 + m(x)))}
What a train wreck!
[Edit]
Ah, that's better!
docs.flatten.foldLeft(Map[String,Int]() withDefaultValue 0){
(m,x) => m + (x -> (1 + m(x)))}
Starting Scala 2.13, after flattening the list of lists, we can use groupMapReduce which is a one-pass alternative to groupBy/mapValues:
// val docs = List(List("one", "two"), List("two", "three"))
docs.flatten.groupMapReduce(identity)(_ => 1)(_ + _)
// Map[String,Int] = Map("one" -> 1, "three" -> 1, "two" -> 2)
This:
flattens the List of Lists as a List
groups list elements (identity) (group part of groupMapReduce)
maps each grouped value occurrence to 1 (_ => 1) (map part of groupMapReduce)
reduces values within a group of values (_ + _) by summing them (reduce part of groupMapReduce).