scala - String split("|") works incorrectly? - scala

I've encountered a strange question on scala String split
here is my code:
scala> val s1 = "oauth_token=FOO&oauth_token_secret=BAR&oauth_expires_in=3600"
s1: String = oauth_token=FOO&oauth_token_secret=BAR&oauth_expires_in=3600
scala> s1.split("&")
res3: Array[String] = Array(oauth_token=FOO, oauth_token_secret=BAR, oauth_expires_in=3600)
so far, the split method works well, but..
scala> val s2 = "oauth_token=FOO|oauth_token_secret=BAR|oauth_expires_in=3600"
s2: String = oauth_token=FOO|oauth_token_secret=BAR|oauth_expires_in=3600
scala> s2.split("|")
res4: Array[String] = Array("", o, a, u, t, h, _, t, o, k, e, n, =, F, O, O, |, o, a, u, t, h, _, t, o, k, e, n, _, s, e, c, r, e, t, =, B, A, R, |, o, a, u, t, h, _, e, x, p, i, r, e, s, _, i, n, =, 3, 6, 0, 0)
the method actually splits out every character, even strangely, an empty string appears at the front.
I have tried other delimiters such as %, ,, the method still works well. It seems that split does not work correctly when | serve as delimiter?

split() expects a regular expression, and in regex-land | means "OR", so you're splitting on the empty string OR on the empty string, which is what you're seeing.
You can use an escape to split on literal |s:
scala> val s2 = "oauth_token=FOO|oauth_token_secret=BAR|oauth_expires_in=3600"
s2: String = oauth_token=FOO|oauth_token_secret=BAR|oauth_expires_in=3600
scala> s2.split("\\|")
res0: Array[String] = Array(oauth_token=FOO, oauth_token_secret=BAR, oauth_expires_in=3600)

Scala has an implicit conversion which provides split() method on strings that accepts char:
scala> val s2 = "oauth_token=FOO|oauth_token_secret=BAR|oauth_expires_in=3600"
s2: String = oauth_token=FOO|oauth_token_secret=BAR|oauth_expires_in=3600
scala> s2.split('|')
res0: Array[String] = Array(oauth_token=FOO, oauth_token_secret=BAR, oauth_expires_in=3600)
Naturally, this only works if your splitter is a single character. If it is a multi-character string, you need to keep track of regex-specific characters yourself.

Related

Scala .map(toString()) gives List of Char

I tried to make my own map method in Scala and this is the result:
def map[A, B](f: A => B)(as: List[A]): List[B] =
for (i <- as) yield f(i)
And if I try to convert a List[Int] to a List[String]:
val list = List(1, 2, 3, 4, 5) //> list : List[Int] = List(1, 2, 3, 4, 5)
map(toString()) (list) //> res0: List[Char] = List(e, b, u, n, g)
I get the same result if I try:
list.map(toString()) //> res1: List[Char] = List(e, b, u, n, g)
My Question: Why gives toString() not a List("1","2"...)?
You're calling toString() on the current object (which apparently returns something like "?ebung...") and passing the resulting string as an argument to map.
So you might expect that to produce a type error because map expects a function, but you're passing a string. However strings count as functions too (because RichString implements the Function1[Int, Char] trait) that take an integer and return the character at that index. So that's why you get a list containing those characters.
To do what you meant to do (create a function that calls toString on its argument), you can either use x => x.toString or _.toString for short.

confusing by scala replaceFirst

scala > val a = (x:Int)=>x+1
res0: Int => Int = <function1>
scala > val b = a.getClass
b: Class[_ <: Int => Int] = class $anonfun$1
scala > b.getName.replaceFirst("^.*\\.", "") + ".class"
//Why there is a prefix '$read$'
res2: String = $read$$anonfun$1.class
I'm confusing about the res2. I think the res2 should be '$anonfun$1.class'.
This one was fun.
scala> val a = ((x: Int) => x).getClass.getName
a: String = $anonfun$1
scala> a == "$anonfun$1"
res2: Boolean = false
Wait, what?
scala> a.getBytes.map(_.toChar)
res3: Array[Char] = Array($, l, i, n, e, 4, ., $, r, e, a, d, $, $, i, w, $, $, i, w, $, $, a, n, o, n, f, u, n, $, 1)
So the name of the class is actually $line4.$read$$iw$$iw$$anonfun$1, not $anonfun$1. But why does Scala REPL print it like this? All executable Scala code must be inside a class, trait, or object definition. So when you enter a line in REPL which isn't, it gets wrapped inside an object. And apparently when printing an answer, REPL suppresses anything which looks like part of this object's generated name, even if it isn't where it comes from:
scala> "a$$iw$$b"
res7: String = a$$b
And $line4.$read$ qualifies for this suppression, but $read$ by itself doesn't.

Scala Random String

Hope you are doing good, I just started scala basic programming, I want to generate some string variable with foreach or something else you think is the best method.
How do I use scala.util.Random to generate this result:
Var 1A:String = random between A to J
Var 1B:String = random between A to J but not 1A value
Var 1C:String = random between A to J, not 1A and not 1B
Var 1D to 1J also should have different random value from A to J
So basically from 1A to 1J could be like this:
Var 1A = "B"
Var 1B = "G"
Var 1C = "A"
Var 1D = "D"
Var 1E = "H"
and so on until 1J
The simplest way is probably to use Random.shuffle.
First construct your list of characters:
scala> val chars = ('A' to 'J').toList
chars: List[Char] = List(A, B, C, D, E, F, G, H, I, J)
Then shuffle them:
scala> val shuffled = scala.util.Random.shuffle(chars)
shuffled: List[Char] = List(C, E, G, B, J, A, F, H, D, I)
Now you've got a list of these ten characters in a random order. If you need variables referring to them, you can do something like this:
scala> val List(a, b, c, d, e, f, g, h, i, j) = shuffled
a: Char = C
b: Char = E
c: Char = G
d: Char = B
e: Char = J
f: Char = A
g: Char = F
h: Char = H
i: Char = D
j: Char = I
(Note that 1A isn't a valid Scala identifier, and Val isn't valid syntax.)
Or you can refer to them by index:
val a = shuffled(0)
val b = shuffled(1)
...
Or you could just work with them in the list.
You can use shuffle from Random package:
scala> scala.util.Random.shuffle(('A' to 'J').toList map (_.toString))
res2: List[String] = List(C, F, D, E, G, A, B, I, H, J)
Assign the result to the list of variables if you like.

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's tuple unwrapping nuance

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()