Scala's tuple unwrapping nuance - scala

I've noticed the following behavior in scala when trying to unwrap tuples into vals:
scala> val (A, B, C) = (1, 2, 3)
<console>:5: error: not found: value A
val (A, B, C) = (1, 2, 3)
^
<console>:5: error: not found: value B
val (A, B, C) = (1, 2, 3)
^
<console>:5: error: not found: value C
val (A, B, C) = (1, 2, 3)
^
scala> val (u, v, w) = (1, 2, 3)
u: Int = 1
v: Int = 2
w: Int = 3
Is that because scala's pattern matching mechanism automatically presumes that all identifiers starting with capitals within patterns are constants, or is that due to some other reason?
Thanks!

Yes, and it gets worse:
val (i, j) : (Int, Int) = "Hello" -> "World"
The above will compile and fail at runtime with a ClassCastException. It is easy to forget that the (i, j) declaration is a pattern.
EDIT: for ziggystar, the Scala assignment rules state that in the statement:
val p = expr //or var
p can be either an identifier or a pattern (see section 15.7 of Programming in Scala, pp284). So for example, the following is valid:
val x :: y :: z :: rest = List(1, 2, 3, 4)
Taking this together with the fact that patterns are erased (i.e. parametric type information is unchecked) means that my original example will compile.

From [scala] Question about naming conventions you can read
The initial capital letter has an advantage when pattern matching. Identifiers with an initial capital letter are considered to be values to match against instead of a variable to be bound.

A workaround exists if you need to initialize a large number of constants and want to avoid writing val = for each or you are hitting the tuple size limit (22).
From section 4.1 of The Scala Language Specification:
A value definition val x: T = e defines x as a name of the value that
results from the evaluation of e. A value definition val p1, ..., pn =
e is a shorthand for the sequence of value definitions val p1 = e; ...;
val pn = e.
Per the specification, one can initialize a sequence of values all with names starting with capital letters by specifying an expression on the right-hand which returns each value in order.
val iter = Iterator(1, 2, 3)
val A, B, C = iter.next()
Another example:
val next = { var n = 0; () => { n = n + 1; n } }
val A, B, C, D, E, F, G, H = next()
In these trivial cases above this approach is not very useful. Below is a more useful example that initializes a constant for each of the 64 squares of the chessboard (see Square.scala#L31 for source):
val squareIter = squares.iterator
val A1, A2, A3, A4, A5, A6, A7, A8,
B1, B2, B3, B4, B5, B6, B7, B8,
C1, C2, C3, C4, C5, C6, C7, C8,
D1, D2, D3, D4, D5, D6, D7, D8,
E1, E2, E3, E4, E5, E6, E7, E8,
F1, F2, F3, F4, F5, F6, F7, F8,
G1, G2, G3, G4, G5, G6, G7, G8,
H1, H2, H3, H4, H5, H6, H7, H8 = squareIter.next()

Related

scala collections : map a list and carry some state?

I seem to run into this problem all the time. I want to modify some of the elements in a list, but I need to keep some state as I do it, so map doesn't work.
Here is an example :
scala> val l1 = List("a","b","c","d","e","f","b","c","e","b","a")
l1: List[String] = List(a, b, c, d, e, f, b, c, e, b, a)
I want to change the name of any duplicates. so I want to end up with this:
List(a1, b1, c1, d, e1, f, b2, c2, e2, b3, a2)
Getting the dupes is easy :
scala> val d = l1.diff(l1.distinct).distinct
d: List[String] = List(b, c, e, a)
Now I'm stuck. I made it work by converting d to a HashMap w/ a count, and writing a function to iterate over l1 and update it & the hash before recursing. Which works fine, but looks kinda ugly to me.
But I've always thought there should be a way to do w/ the collection classes.
Here is the rest of my solution which I don't like :
val m = d.map( _ -> 1).toMap
def makeIt(ms: Map[String, Int], ol: Iterator[String], res: List[String]=List[String]()) :List[String] = {
if( !ol.hasNext) return res
val no = ol.next()
val (p,nm) = ms.get(no) match {
case Some(v) => (s"$no$v", ms.updated(no,v+1))
case None => (no,ms)
}
makeIt(nm,ol,res :+ p)
}
makeIt(m,l1.iterator)
Which gives me what I want
res2: List[String] = List(a1, b1, c1, d, e1, f, b2, c2, e2, b3, a2)
I feel like I want "mapWithState" where I can just pass something along. Like Fold-ish. Maybe it exists and I just haven't found it yet?
Thanks
-------UPDATE---------
#Aluan Haddad's comment pointed me in this direction. Which destroys order, which is fine for my case. But the "state" is carried by zipWithIndex. I'm looking for a more general case where the state would require some computation at each element. But for this simple case I like it :
l1.groupBy(x=>x).values.flatMap( v =>{
if( v.length <= 1 ) v else {
v.zipWithIndex.map{ case (s,i) => s"$s${i+1}"}
}
})
res7: Iterable[String] = List(e1, e2, f, a1, a2, b1, b2, b3, c1, c2, d)
The tricky part is that the "d" and "f" elements get no modification.
This is what I came up with. It's a bit more concise, code wise, but does involve multiple traversals.
val l1: List[String] = List("a","b","c","d","e","f","b","c","e","b","a")
l1.reverse.tails.foldLeft(List[String]()){
case (res, Nil) => res
case (res, hd::tl) =>
val count = tl.count(_ == hd)
if (count > 0) s"$hd${count+1}" +: res
else if (res.contains(hd+2)) (hd+1) +: res
else hd +: res
}
//res0: List[String] = List(a1, b1, c1, d, e1, f, b2, c2, e2, b3, a2)
By using tails, each element, hd, is able to see the future, tl, and the past, res.
A simple but slow version
l1.zipWithIndex.map{ case (elem, i) =>
if (l1.count(_ == elem) == 1) {
elem
} else {
val n = {l1.take(i+1).count(_ == elem)}
s"$elem$n"
}
}
The next version is longer, less pretty, and not functional, but should be faster in the unlikely case that you are processing a very long list.
def makeUniq(in: Seq[String]): Seq[String] = {
// Count occurrence of each element
val m = mutable.Map.empty[String, Int]
for (elem <- in) {
m.update(elem, m.getOrElseUpdate(elem, 0) + 1)
}
// Remove elements with a single occurrence
val dupes = m.filter(_._2 > 1)
// Apply numbering to duplicate elements
in.reverse.map(e => {
val idx = dupes.get(e) match {
case Some(i) =>
dupes.update(e, i - 1)
i.toString
case _ =>
""
}
s"$e$idx"
}).reverse
}
The code is easier if you wanted to apply a count to every element rather than just the non-unique ones.
def makeUniq(in: Seq[String]): Seq[String] = {
val m = mutable.Map.empty[String, Int]
in.map{ e =>
val i = m.getOrElseUpdate(e, 0) + 1
m.update(e, i)
s"$e$i"
}
}

How to implement generic function in Scala with two argument types?

I'd like to implement a function in Scala that computes the dot product of two numeric sequences as follows
val x = Seq(1,2,3.0)
val y = Seq(4,5,6)
val z = (for (a <- x; b <- y) yield a*b).sum
scala> z : Double = 90.0
val x = Seq(1,2,3)
val y = Seq(4,5,6)
val z = (for (a <- x; b <- y) yield a*b).sum
scala> z : Int = 90
Notice that if the two sequences are of different types, the result is an Double. If the two sequences are of the same type (e.g. Int), the result is an Int.
I came up with two alternatives but neither meets the requirement as defined above.
Alternative #1:
def dotProduct[T: Numeric](x: Seq[T], y: Seq[T]): T = (for (a <- x; b <- y) yield implicitly[Numeric[T]].times(a, b)).sum
This returns the result in the same type as the input, but it can't take two different types.
Alternative #2:
def dotProduct[A, B](x: Seq[A], y: Seq[B])(implicit nx: Numeric[A], ny: Numeric[B]) = (for (a <- x; b <- y) yield nx.toDouble(a)*ny.toDouble(b)).sum
This works for all numeric sequences. However, it always return a Double, even if the two sequences are of the type Int.
Any suggestion is greatly appreciated.
p.s. The function I implemented above is not "dot product", but simply sum of product of two sequences. Thanks Daniel for pointing it out.
Alternative #3 (slightly better than alternatives #1 and #2):
def sumProduct[T, A <% T, B <% T](x: Seq[A], y: Seq[B])(implicit num: Numeric[T]) = (for (a <- x; b <- y) yield num.times(a,b)).sum
sumProduct(Seq(1,2,3), Seq(4,5,6)) //> res0: Int = 90
sumProduct(Seq(1,2,3.0), Seq(4,5,6)) //> res1: Double = 90.0
sumProduct(Seq(1,2,3), Seq(4,5,6.0)) // Fails!!!
Unfortunately, the View Bound feature (e.g. "<%") will be deprecated in Scala 2.10.
You could create a typeclass that represents the promotion rules:
trait NumericPromotion[A, B, C] {
def promote(a: A, b: B): (C, C)
}
implicit object IntDoublePromotion extends NumericPromotion[Int, Double, Double] {
def promote(a: Int, b: Double): (Double, Double) = (a.toDouble, b)
}
def dotProduct[A, B, C]
(x: Seq[A], y: Seq[B])
(implicit numEv: Numeric[C], promEv: NumericPromotion[A, B, C])
: C = {
val foo = for {
a <- x
b <- y
} yield {
val (pa, pb) = promEv.promote(a, b)
numEv.times(pa, pb)
}
foo.sum
}
dotProduct[Int, Double, Double](Seq(1, 2, 3), Seq(1.0, 2.0, 3.0))
My typeclass-fu isn't good enough to eliminate the explicit type parameters in the call to dotProduct, nor could I figure out how to avoid the val foo inside the method; inlining foo led to compiler errors. I chalk this up to no having really internalized the implicit resolution rules. Maybe somebody else can get you further.
It's also worth mentioning that this is directional; you couldn't compute dotProduct(Seq(1.0, 2.0, 3.0), Seq(1, 2, 3)). But that's easy to fix:
implicit def flipNumericPromotion[A, B, C]
(implicit promEv: NumericPromotion[B, A, C])
: NumericPromotion[A, B, C] =
new NumericPromotion[A, B, C] {
override def promote(a: A, b: B): (C, C) = promEv.promote(b, a)
}
It's also worth mentioning that your code doesn't compute a dot product. The dot product of [1, 2, 3] and [4, 5, 6] is 4 + 10 + 18 = 32.

scala partial string match

I have a question about List of Strings partial Matching to a List of Strings (intersect I guess).
List1:List = [a,b,c,d,e,f]
List2:Iterable[String] = [a b,e f,g h,x y]
I want to take any element or combination of elements in List1 that also happens to be in List2, and replace it with the element in List2, for example, [a,b] are in List1, List 2 contains element [a b], in this case, [a,b] in List1 will be replaced with [a b]. The result for List 1 should be:
List1result = [a b,c,d,e f]
I've tried intersect, which would return [a b, e f]
Ok, I edited my answer after the comment bellow, I think I understood the question now.
take each element of the second list, convert it into a list of elements and use containsSlice to filter out the value.
containsSlice will return true if all the elements in the slice are present in the first list.
val lst1 = List("a","b","c","d","e","f")
val lst2 = List("a b","e f","g h","x y")
lst2.filter{ pair =>
val xss = pair.split(" ")
lst1.containsSlice(xss)
}
You can try something like this :
val l1 = List("a", "b", "c", "d", "e", "f")
val l2 = List("a b", "e f", "g h", "x y")
l1.filterNot(x=>l2.flatten.filter(_ != ' ').contains(x.toCharArray.head))
l2.foldLeft(List[String]()) { case (x, y) => if (l1.containsSlice(y.split(" "))) x :+ y else x} ++
l1.filterNot(x=>l2.flatten.filter(_ != ' ').contains(x.toCharArray.head))
l1: List[String] = List(a, b, c, d, e, f)
l2: List[String] = List(a b, e f, g h, x y)
res0: List[String] = List(a b, e f, c, d)

Transposing arbitrary collection-of-collections in Scala

I have to often transpose a "rectangular" collection-of-collections in Scala, e.g.: a list of maps, a map of lists, a map of maps, a set of lists, a map of sets etc. Since collections can be uniformly viewed as a mapping from a specific domain to a co-domain (e.g.: a List[A]/Array[A] is a mapping from the Int domain to the A co-domain, Set[A]is a mapping from the A domain to the Boolean co-domain etc.), I'd like to write a clean, generic function to do a transpose operation (e.g.: turn a map of lists to the transposed list of maps). However, I'm having trouble because other than the () operator, Scala doesn't seem to have a unified API to view collections abstractly as mappings ?
So I end up writing a separate transpose for each type of collection-of-collections as follows:
def transposeMapOfLists[A,B]( mapOfLists: Map[A,List[B]] ) : List[Map[A,B]] = {
val k = ( mapOfLists keys ) toList
val l = ( k map { mapOfLists(_) } ) transpose;
l map { v => ( k zip v ) toMap }
}
def transposeListOfMaps[A,B]( listOfMaps: List[Map[A,B]]) : Map[A,List[B]] = {
val k = ( listOfMaps(0) keys ) toList
val l = ( listOfMaps map { m => k map { m(_) } } ) transpose;
( k zip l ) toMap
}
def transposeMapOfMaps[A,B,C]( mapOfMaps: Map[A,Map[B,C]] ) : Map[B,Map[A,C]] = {
val k = ( mapOfMaps keys ) toList
val listOfMaps = k map { mapOfMaps(_) }
val mapOfLists = transposeListOfMaps( listOfMaps )
mapOfLists map { p => ( p._1, ( k zip p._2 ) toMap ) }
}
Can someone help me unify these methods into one generic collection-of-collections transpose ? It will also help me (and I am sure others) learn some useful Scala features in the process.
ps: I have ignored exception handling and have assumed the input collection-of-collections is rectangular, i.e., all of the inner collections' domain elements constitute the same set.
I'm sure the following messy version using type classes could be cleaned up a lot, but it works as a quick proof-of-concept. I don't see an easy way to get the return types right without dependent method types (I'm sure it's possible), so you'll have to use -Xexperimental:
trait Mapping[A, B, C] {
type M[D] <: PartialFunction[A, D]
def domain(c: C): Seq[A]
def fromPairs[D](ps: Seq[(A, D)]): M[D]
def codomain(c: C)(implicit ev: C <:< PartialFunction[A, B]) =
domain(c).map(c)
def toPairs(c: C)(implicit ev: C <:< PartialFunction[A, B]) =
domain(c).map(a => (a, c(a)))
}
implicit def seqMapping[A, B <: Seq[A]] = new Mapping[Int, A, B] {
type M[C] = Seq[C]
def domain(c: B) = 0 until c.size
def fromPairs[C](ps: Seq[(Int, C)]) = ps.sortBy(_._1).map(_._2)
}
implicit def mapMapping[A, B, C <: Map[A, B]] = new Mapping[A, B, C] {
type M[D] = Map[A, D]
def domain(c: C) = c.keys.toSeq
def fromPairs[D](ps: Seq[(A, D)]) = ps.toMap
}
def transpose[A, B, C, M, N](m: M)(implicit
pev: M <:< PartialFunction[A, N],
qev: N <:< PartialFunction[B, C],
mev: Mapping[A, N, M],
nev: Mapping[B, C, N]
) = nev.fromPairs(nev.domain(mev.codomain(m).head).map(b =>
b -> mev.fromPairs(mev.toPairs(m).map { case (a, c) => a -> c(b) })
))
And now for some tests:
scala> println(transpose(List(Map("a" -> 1, "b" -> 13), Map("b" -> 99, "a" -> 14))))
Map(a -> Vector(1, 14), b -> Vector(13, 99))
scala> println(transpose(Map('a' -> List(1, 2, 3), 'z' -> List(4, 5, 6))))
Vector(Map(a -> 1, z -> 4), Map(a -> 2, z -> 5), Map(a -> 3, z -> 6))
scala> println(transpose(Map("x" -> Map(4 -> 'a, 99 -> 'z), "y" -> Map(4 -> 'b, 99 -> 's))))
Map(4 -> Map(x -> 'a, y -> 'b), 99 -> Map(x -> 'z, y -> 's))
So it's working as desired.

Cartesian product of two lists

Given a map where a digit is associated to several characters
scala> val conversion = Map("0" -> List("A", "B"), "1" -> List("C", "D"))
conversion: scala.collection.immutable.Map[java.lang.String,List[java.lang.String]] =
Map(0 -> List(A, B), 1 -> List(C, D))
I want to generate all possible character sequences based on a sequence of digits. Examples:
"00" -> List("AA", "AB", "BA", "BB")
"01" -> List("AC", "AD", "BC", "BD")
I can do this with for comprehensions
scala> val number = "011"
number: java.lang.String = 011
Create a sequence of possible characters per index
scala> val values = number map { case c => conversion(c.toString) }
values: scala.collection.immutable.IndexedSeq[List[java.lang.String]] =
Vector(List(A, B), List(C, D), List(C, D))
Generate all the possible character sequences
scala> for {
| a <- values(0)
| b <- values(1)
| c <- values(2)
| } yield a+b+c
res13: List[java.lang.String] = List(ACC, ACD, ADC, ADD, BCC, BCD, BDC, BDD)
Here things get ugly and it will only work for sequences of three digits. Is there any way to achieve the same result for any sequence length?
The following suggestion is not using a for-comprehension. But I don't think it's a good idea after all, because as you noticed you'd be tied to a certain length of your cartesian product.
scala> def cartesianProduct[T](xss: List[List[T]]): List[List[T]] = xss match {
| case Nil => List(Nil)
| case h :: t => for(xh <- h; xt <- cartesianProduct(t)) yield xh :: xt
| }
cartesianProduct: [T](xss: List[List[T]])List[List[T]]
scala> val conversion = Map('0' -> List("A", "B"), '1' -> List("C", "D"))
conversion: scala.collection.immutable.Map[Char,List[java.lang.String]] = Map(0 -> List(A, B), 1 -> List(C, D))
scala> cartesianProduct("01".map(conversion).toList)
res9: List[List[java.lang.String]] = List(List(A, C), List(A, D), List(B, C), List(B, D))
Why not tail-recursive?
Note that above recursive function is not tail-recursive. This isn't a problem, as xss will be short unless you have a lot of singleton lists in xss. This is the case, because the size of the result grows exponentially with the number of non-singleton elements of xss.
I could come up with this:
val conversion = Map('0' -> Seq("A", "B"), '1' -> Seq("C", "D"))
def permut(str: Seq[Char]): Seq[String] = str match {
case Seq() => Seq.empty
case Seq(c) => conversion(c)
case Seq(head, tail # _*) =>
val t = permut(tail)
conversion(head).flatMap(pre => t.map(pre + _))
}
permut("011")
I just did that as follows and it works
def cross(a:IndexedSeq[Tree], b:IndexedSeq[Tree]) = {
a.map (p => b.map( o => (p,o))).flatten
}
Don't see the $Tree type that am dealing it works for arbitrary collections too..