Given a regex and a string
val reg = "(a)(b)"
val str = "ab"
and a corresponding case class
case class Foo(a: string, b: string)
How can I match the regex against the string and unapply the matches
into the case class so I have
Foo("a", "b")
in the end?
Pattern match on the result of finding the regular expression in the string and assigning the results to Foo. The API docs for Regex have a similar example.
scala> val reg = "(a)(b)".r
reg: scala.util.matching.Regex = (a)(b)
scala> val str = "ab"
str: String = ab
scala> case class Foo(a: String, b: String)
defined class Foo
scala> val foo = reg.findFirstIn(str) match{
| case Some(reg(a,b)) => new Foo(a,b)
| case None => Foo("","")
| }
foo: Foo = Foo(a,b)
scala> foo.a
res2: String = a
scala> foo.b
res3: String = b
If you are sure that the match is ok, you can currify the function and use a foldleft to apply this version to the list of extracted arguments:
> val reg = "(a)(b)".r
> val str = "ab"
> val f1 = (Foo.apply _).curried
// f1 : String => String => Foo
> val groups = reg.findFirstMatchIn(str).get.subgroups
// groups: List[String]
> val foo = ((f1 : Any) /: groups) { case (f: (String => Any), s) => f(s)} asInstanceOf[Foo]
foo: Foo = Foo(a,b)
See Function2 in scala for the definition of curried.
Related
Why does Scala have both unapply and unapplySeq? What is the difference between the two? When should I prefer one over the other?
Without going into details and simplifying a bit:
For regular parameters apply constructs and unapply de-structures:
object S {
def apply(a: A):S = ... // makes a S from an A
def unapply(s: S): Option[A] = ... // retrieve the A from the S
}
val s = S(a)
s match { case S(a) => a }
For repeated parameters, apply constructs and unapplySeq de-structures:
object M {
def apply(a: A*): M = ......... // makes a M from an As.
def unapplySeq(m: M): Option[Seq[A]] = ... // retrieve the As from the M
}
val m = M(a1, a2, a3)
m match { case M(a1, a2, a3) => ... }
m match { case M(a, as # _*) => ... }
Note that in that second case, repeated parameters are treated like a Seq and the similarity between A* and _*.
So if you want to de-structure something that naturally contains various single values, use unapply. If you want to de-structure something that contains a Seq, use unapplySeq.
Fixed-arity vs. variable arity. Pattern Matching in Scala (pdf) explains it well, with mirroring examples. I also have mirroring examples in this answer.
Briefly:
object Sorted {
def unapply(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
object SortedSeq {
def unapplySeq(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
scala> List(1,2,3,4) match { case Sorted(xs) => xs }
res0: Seq[Int] = List(1, 2, 3, 4)
scala> List(1,2,3,4) match { case SortedSeq(a, b, c, d) => List(a, b, c, d) }
res1: List[Int] = List(1, 2, 3, 4)
scala> List(1) match { case SortedSeq(a) => a }
res2: Int = 1
So, which do you think is exhibited in the following example?
scala> List(1) match { case List(x) => x }
res3: Int = 1
Some examples:
scala> val fruit = List("apples", "oranges", "pears")
fruit: List[String] = List(apples, oranges, pears)
scala> val List(a, b, c) = fruit
a: String = apples
b: String = oranges
c: String = pears
scala> val List(a, b, _*) = fruit
a: String = apples
b: String = oranges
scala> val List(a, _*) = fruit
a: String = apples
scala> val List(a,rest # _*) = fruit
a: String = apples
rest: Seq[String] = List(oranges, pears)
scala> val a::b::c::Nil = fruit
a: String = apples
b: String = oranges
c: String = pears
scala> val a::b::rest = fruit
a: String = apples
b: String = oranges
rest: List[String] = List(pears)
scala> val a::rest = fruit
a: String = apples
rest: List[String] = List(oranges, pears)
what is the difference between case x:Int and case x # Int? In the following example, why doesn't case x#Int gets matched when an Int argument is passed?
scala> def matchInt (x:Any) = x match {
| case x:Int => println("got int"+x) //this matches with Int
| case _ => println("no int "+x)
| }
matchInt: (x: Any)Unit
scala> matchInt(1)
got int1
scala> matchInt("2")
no int 2
scala> def matchInt (x:Any) = x match {
| case x # Int => println("got int"+x) //this doesn't matches with Int
| case _ => println("no int "+x)
| }
matchInt: (x: Any)Unit
scala> matchInt("2")
no int 2
scala> matchInt(1)
no int 1
scala>
x:Int means "x of type Int". x#Int means "x that is a type Int".
The latter is pretty useless in this case.
We use x: Int for Type pattern matching and at times you may want to add a variable to a pattern. You can do this with the following general syntax: variableName # pattern.
For x: Int your pattern matching is fine to match the type of the x.
For variableName # pattern, look the example where we are matching a various pattern:
scala> case class Test(t1: String, t2: String)
defined class Test
scala> object Test2 extends App {
| def matchType(x: Any): String = x match {
| case y # List(1, _*) => s"$y" // works; prints the list
| case y # Some(_) => s"$y" // works, returns "Some(Hiii)"
| case y # Test("t1", "t2") => s"$y" // works, returns "Test(t1,t2)"
| }
| }
defined object Test2
scala> Test2.matchType(List(1,2,3))
res2: String = List(1, 2, 3)
scala> Test2.matchType(Some("Hiii"))
res3: String = Some(Hiii)
scala> Test2.matchType(Test("t1","t2"))
res4: String = Test(t1,t2)
I need to define val tuple in my scala case classe as value parameter
case class (v1:(a:String, b:String), v2:String)
but it gives me a compilation error..can someone point me how to that?
You can't name the tuple elements in the class parameters, but you can in the class body.
scala> case class CC(v1:(String, String), v2:String) {
| val (a,b) = v1
| }
defined class CC
scala> val cc = CC(("X", "Y"), "Z")
cc: CC = CC((X,Y),Z)
scala> cc.a
res11: String = X
scala> cc.b
res12: String = Y
Using the REPL, note the inferred type for a given value; for instance
scala> val t = ("a","b")
t: (String, String) = (a,b)
Hence
scala> val t2: (String,String) = ("a","b")
t2: (String, String) = (a,b)
case class v1(t: (String, String), v2: String)
Given:
scala> case class ParentPath(private val x: String) {
| val value = x.dropWhile(_ == '/')
| }
I can make a ParentPath:
scala> ParentPath("/foo")
res10: ParentPath = ParentPath(/foo)
I can't access its x (due to private, it appears).
scala> res10.
asInstanceOf canEqual copy isInstanceOf productArity productElement productIterator productPrefix toString value
I can get its value.
scala> res10.value
res11: String = foo
However, I'd prefer to return its value rather than x upon a pattern match:
scala> res10 match { case ParentPath(x) => x}
res13: String = /foo
How can I pattern match with value rather than x?
scala> ParentPath.unapply(res10)
res15: Option[String] = Some(/foo)
I tried to override ParentPath#unapply, but got a compile-time error:
scala> case class ParentPath(private val x: String) {
| val value = "foo"
| override def unapply(p: ParentPath): Option[String] = Some(value)
| }
<console>:15: error: method unapply overrides nothing
override def unapply(p: ParentPath): Option[String] = Some(value)
^
The unapply method belongs in the companion object, and you cannot override it for a case class, anyway. For a normal class, this will work. Or, if you simply use a differently named object that has an unapply method of the same signature.
class ParentPath(private val x: String) {
val value = "foo"
}
object ParentPath {
def unapply(p: ParentPath): Option[String] = Some(p.value)
}
scala> new ParentPath("/foo") match { case ParentPath(x) => x }
res1: String = foo
Why does Scala have both unapply and unapplySeq? What is the difference between the two? When should I prefer one over the other?
Without going into details and simplifying a bit:
For regular parameters apply constructs and unapply de-structures:
object S {
def apply(a: A):S = ... // makes a S from an A
def unapply(s: S): Option[A] = ... // retrieve the A from the S
}
val s = S(a)
s match { case S(a) => a }
For repeated parameters, apply constructs and unapplySeq de-structures:
object M {
def apply(a: A*): M = ......... // makes a M from an As.
def unapplySeq(m: M): Option[Seq[A]] = ... // retrieve the As from the M
}
val m = M(a1, a2, a3)
m match { case M(a1, a2, a3) => ... }
m match { case M(a, as # _*) => ... }
Note that in that second case, repeated parameters are treated like a Seq and the similarity between A* and _*.
So if you want to de-structure something that naturally contains various single values, use unapply. If you want to de-structure something that contains a Seq, use unapplySeq.
Fixed-arity vs. variable arity. Pattern Matching in Scala (pdf) explains it well, with mirroring examples. I also have mirroring examples in this answer.
Briefly:
object Sorted {
def unapply(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
object SortedSeq {
def unapplySeq(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
scala> List(1,2,3,4) match { case Sorted(xs) => xs }
res0: Seq[Int] = List(1, 2, 3, 4)
scala> List(1,2,3,4) match { case SortedSeq(a, b, c, d) => List(a, b, c, d) }
res1: List[Int] = List(1, 2, 3, 4)
scala> List(1) match { case SortedSeq(a) => a }
res2: Int = 1
So, which do you think is exhibited in the following example?
scala> List(1) match { case List(x) => x }
res3: Int = 1
Some examples:
scala> val fruit = List("apples", "oranges", "pears")
fruit: List[String] = List(apples, oranges, pears)
scala> val List(a, b, c) = fruit
a: String = apples
b: String = oranges
c: String = pears
scala> val List(a, b, _*) = fruit
a: String = apples
b: String = oranges
scala> val List(a, _*) = fruit
a: String = apples
scala> val List(a,rest # _*) = fruit
a: String = apples
rest: Seq[String] = List(oranges, pears)
scala> val a::b::c::Nil = fruit
a: String = apples
b: String = oranges
c: String = pears
scala> val a::b::rest = fruit
a: String = apples
b: String = oranges
rest: List[String] = List(pears)
scala> val a::rest = fruit
a: String = apples
rest: List[String] = List(oranges, pears)