Suppose I have a method like this:
def func(strs: String*) = {
//Do something
}
That means that the function can take an undefined number of strings as arguments, right? Then, why can I do this
func("hello", "world")
or this
val strArr = Array("hello", "world")
func(str: _*)
but not this?
val strArr = Array("hello", "world")
func("foo", strArr: _*)
Related
Let's i code speaking:)
class TagCalculation {
def test_string(arg1: String,arg2: String) = arg1 + " " + arg2
def test_int(arg1: Int,arg2: Int) = arg1 + arg2
def test_mix1(arg1:Int,arg2:String) = "test mix1"
def test_mix2(arg1:Int,arg2:String,arg3:List[Any]) = "test mix2"
}
val get_test = new TagCalculation
//test mix2
val test_mix2_para = Array(1, "aa",List(1,2))
val argtypes4 = test_mix2_para.map(_.getClass)
val method4 = get_test.getClass.getMethod("test_mix2", argtypes4: _*)
Then the error outputs:
scala> val argtypes4 = test_mix2_para.map(.getClass) argtypes4:
Array[Class[]] = Array(class java.lang.Integer, class
java.lang.String, class scala.collection.immutable.$colon$colon)
scala> val method4 = get_test.getClass.getMethod("test_mix2",
argtypes4: _*) java.lang.NoSuchMethodException:
$iwC$$iwC$TagCalculation.test_mix2(java.lang.Integer,
java.lang.String, scala.collection.immutable.$colon$colon) at
java.lang.Class.getMethod(Class.java:1678) at
$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC.(:26) at
$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC.(:31)
Could somebody give me some help?
I ran into the same problem, and found that it worked by using certain types and telling the compiler exactly what you were up to. In your case you can use a java.lang.Integer instead of a regular Int and additionally get really specific with the List type. This example is working:
class TagCalculation {
def test(arg1: java.lang.Integer, arg2: String, arg3: scala.collection.immutable.$colon$colon[Any]) = "test mix2"
}
val getTest = new TagCalculation
val arg1: java.lang.Integer = 10
val arg2: String = "foobar"
// Just making a List[Any]
val arg3: scala.collection.immutable.$colon$colon[Any] = scala.collection.immutable.$colon$colon.apply('z', List("foo", 10))
val method = getTest.getClass.getMethod("test", arg1.getClass, arg2.getClass, arg3.getClass)
method.invoke(getTest, arg1, arg2, arg3)
Unfortunately I don't know why this is the case.
You need to call getMethod with exactly the classes the method is declared with, it doesn't work otherwise:
get_test.getClass.getMethod("test_mix2", classOf[Int], classOf[String], classOf[List[Any]])
(the type parameter to List does not matter because of type erasure). If you look at argtypes4, it doesn't contain these classes: putting 1 into Array together with objects boxes it to java.lang.Integer, and List(1, 2) returns a :: (which is translated to $colon$colon because : is not a legal character in a JVM identifier) which is a subclass of List.
In the below code, encoded is a JSON string. The JSON.parseFull() function is returning an object of the form: Some(Map(...)). I am using .get to extract the Map, but am unable to index it as the compiler sees it as type Any. Is there any to provide the compiler visibility that it is, in fact, a map?
val parsed = JSON.parseFull(encoded)
val mapped = parsed.get
You can utilize the collect with pattern matching to match on the type:
scala> val parsed: Option[Any] = Some(Map("1" -> List("1")))
parsed: Option[Any] = Some(Map(1 -> List(1)))
scala> val mapped = parsed.collect{
case map: Map[String, Any] => map
}
mapped: Option[Map[String,Any]] = Some(Map(1 -> List(1)))
You can do something like the following in the case of a List value to get values from the List:
scala> mapped.get.map{ case(k, List(item1)) => item1}
res0: scala.collection.immutable.Iterable[Any] = List(1)
I was able to use a combination of the get function and pattern matching similar to what was posted in Tanjin's response to get the desired result.
object ReadFHIR {
def fatal(msg: String) = throw new Exception(msg)
def main (args: Array[String]): Unit = {
val fc = new FhirContext()
val client = fc.newRestfulGenericClient("http://test.fhir.org/r2")
val bundle = client.search().forResource("Observation")
.prettyPrint()
.execute()
val jsonParser = fc.newJsonParser()
val encoded = jsonParser.encodeBundleToString(bundle)
val parsed = JSON.parseFull(encoded)
val mapped: Map[String, Any] = parsed.get match{
case map: Map[String, Any] => map
}
println(mapped("resourceType"))
}
}
I am trying to get the first 2 values of a comma separated string in scala. For example
a,b,this is a test
How do i store the values a,b in 2 separate variables?
To keep it easy and clean.
KISS solution:
1.Use split for separation. Then use take which is defined on all ordered sequences to get the elements as needed:
scala> val res = "a,b,this is a test" split ',' take 2
res: Array[String] = Array(a, b)
2.Use Pattern matching to set the variables:
scala> val Array(x,y) = res
x: String = a
y: String = b*
Another solution using Sequence Pattern match in Scalaenter link description here
Welcome to Scala version 2.11.2 (OpenJDK 64-Bit Server VM, Java 1.7.0_65).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val str = "a,b,this is a test"
str: String = a,b,this is a test
scala> val Array(x, y, _*) = str.split(",")
x: String = a
y: String = b
scala> println(s"x = $x, y = $y")
x = a, y = b
Are you looking for the method split ?
"a,b,this is a test".split(',')
res0: Array[String] = Array(a, b, this is a test)
If you want only the first two values you'll need to do something like:
val splitted = "a,b,this is a test".split(',')
val (first, second) = (splitted(0), splitted(1))
There should be some regex options here.
scala> val s = "a,b,this is a test"
s: String = a,b,this is a test
scala> val r = "[^,]+".r
r: scala.util.matching.Regex = [^,]+
scala> r findAllIn s
res0: scala.util.matching.Regex.MatchIterator = non-empty iterator
scala> .toList
res1: List[String] = List(a, b, this is a test)
scala> .take(2)
res2: List[String] = List(a, b)
scala> val a :: b :: _ = res2
a: String = a
b: String = b
but
scala> val a :: b :: _ = (r findAllIn "a" take 2).toList
scala.MatchError: List(a) (of class scala.collection.immutable.$colon$colon)
... 33 elided
or if you're not sure there is a second item, for instance:
scala> val r2 = "([^,]+)(?:,([^,]*))?".r.unanchored
r2: scala.util.matching.UnanchoredRegex = ([^,]+)(?:,([^,]*))?
scala> val (a,b) = "a" match { case r2(x,y) => (x, Option(y)) }
a: String = a
b: Option[String] = None
scala> val (a,b) = s match { case r2(x,y) => (x, Option(y)) }
a: String = a
b: Option[String] = Some(b)
This is a bit nicer if records are long strings.
Footnote: the Option cases look nicer with a regex interpolator.
If your string is short, you may as well just use String.split and take the first two elements.
val myString = "a,b,this is a test"
val splitString = myString.split(',') // Scala adds a split-by-character method in addition to Java's split-by-regex
val a = splitString(0)
val b = splitString(1)
Another solution would be to use a regex to extract the first two elements. I think it's quite elegant.
val myString = "a,b,this is a test"
val regex = """(.*),(.*),.*""".r // all groups (in parenthesis) will be extracted.
val regex(a, b) = myString // a="a", b="b"
Of course, you can tweak the regex to only allow non-empty tokens (or anything else you might need to validate) :
val regex = """(.+),(.+),.+""".r
Note that in my examples I assumed that the string always had at least two tokens. In the first example, you can test the length of the array if needed. The second one will throw a MatchError if the regex doesn't match the string.
I had originally proposed the following solution. I will leave it because it works and doesn't use any class formally marked as deprecated, but the Javadoc for StringTokenizer mentions that it is a legacy class and should no longer be used.
val myString = "a,b,this is a test"
val st = new StringTokenizer(",");
val a = st.nextToken()
val b = st.nextToken()
// You could keep calling st.nextToken(), as long as st.hasMoreTokens is true
How is my attempt at implementing Functional Programming in Scala's below exercise?
// EXERCISE 5: Write a monoid instance for that String inserts spaces
// between words unless there already is one, and trims spaces off the ends of the
// result.
def trimMonoid = new Monoid[String] {
def op(a1: String, a2: String) = a1.trim + " " + a2.trim
val zero = ""
}
Is this the proper way to test the monoid? Here's the function signature, but I'm not sure how to implement with what I have: def trimMonoid(s: String): Monoid[String].
object MonoidTesting {
def main(args: Array[String]) = {
val words = List("Hic", "Est", "Barbarus")
val res = trimMonoid.op( ("Hic"), (trimMonoid.op("est ", "chorda ")) )
println("res : " + res)
assert(res == "Hic est chorda")
println("success")
}
}
One of the use cases of Monoid is in fold. I guess in Scala you have foldLeft and foldRight that you can use to test it on the list of string
val res = words.foldLeft(trimMonoid.zero)(trimMonoid.op _)
I am not sure if your trimMonoid does correctly what the exercise asks for, but anyways if its for testing then you could test it better this way:
scala> val xs = List("hey","hi","hello")
xs: List[String] = List(hey, hi, hello)
scala> xs.foldLeft(trimMonoid.zero)((x,y)=> trimMonoid.op(x,y))
res2: String = hey hi hello
I want to have class that can be instantiated with list, array, seq, set, stack, queue etc.
In my opinion
class A
class B(elems:A*)
should handle such stuff.
This is my solution:
class A
class B(elems:Iterable[A]){
def this(elem:A) = this(Seq(elem))
}
Can you suggest any improvements?
Any Seq or Array may be passed to a method with repeated parameters by using the : _* ascription:
scala> def m1(strs: String*): Int = { strs.foldLeft(0)(_ + _.length) }
m1: (strs: String*)Int
scala> m1("foo", "bar")
res0: Int = 6
scala> val ss1 = Array("hello", ", ", "world", ".")
ss1: Array[java.lang.String] = Array(hello, , , world, .)
scala> m1(ss1: _*)
res1: Int = 13
scala> val ss2 = List("now", "is", "the", "time")
ss2: List[java.lang.String] = List(now, is, the, time)
scala> m1(ss2: _*)
res2: Int = 12
This might be a minor improvement.
class A
class B(elems:Iterable[A]){
def this(elem:A*) = this(elem.asInstanceOf[Iterable[A]])
}
That'll make these legal
val b1 = new B(a1)
val b2 = new B(a2, a3)