Pattern matching in conjunciton with filter - scala

given the following code that I#d like to refactor - Im only interested in lines matching the 1st pattern that occurs, is there a way of shortening this like lets say to use it in conjunction with filter?
With best regards,
Stefan
def processsHybridLinks(it: Iterator[String]): Unit =
{
for (line <- it) {
val lineSplit = lineSplitAndFilter(line)
lineSplit match {
case Array(TaggedString(origin), TaggedString(linkName), TaggedString(target), ".") =>
{
println("trying to find pages " + origin + " and " + target)
val originPageOpt = Page.findOne(MongoDBObject("name" -> (decodeUrl(origin))))
val targetPageOpt = Page.findOne(MongoDBObject("name" -> (decodeUrl(target))))
(originPageOpt, targetPageOpt) match {
case (Some(origin), Some(target)) =>
createHybridLink(origin, linkName, target)
Logger.info(" creating Hybrid Link")
case _ => Logger.info(" couldnt create Hybrid LInk")
}
}
case _ =>
}
}
}

Have a look at collect method. It allows you to use a PartialFunction[A,B] defined using an incomplete pattern match as a sort of combination map and filter:
it.map(lineSplitAndFilter) collect {
case Array(TaggedString(o), TaggedString(n), TaggedString(t), ".") =>
(n, Page.findOne(...), Page.findOne(...))
} foreach {
case (n, Some(o), Some(t)) => ...
case _ =>
}

Related

Efficient way to compare result and send a custom object in scala

val date2 = Option(LocalDate.parse("2017-02-01"))
case class dummy(val prop:Seq[Test])
case class Test(val s :String,val dt:String)
case class Result(val s :String)
def myFunc:Result = {
val s = "11,22,33"
val t = Test(s,"2017-02-06")
val list = dummy(Seq(t))
val code = Option("22")
val result = code.exists(p => {
list.prop.exists(d => d.s.split(",").contains(p) && (LocalDate.parse(d.dt).compareTo(date2.get)>=0))
})
if (result) {
Result("found")
} else {
Result("Not Found")
}
}
The code determines the result based on condition.
Is there a efficient way to achieve the above in scala using map and avoiding date2.get
You should check pattern matching, as far as i can see, you have several cases:
- Code
- list
- date2
One way to avoid date2.get is this one belows:
(code, list, date2) match {
case (Some(p), dummy(l), Some(d2)) if l.exists(d => d.s.split(",").contains(p) && (LocalDate.parse(d.dt).compareTo(d2) >= 0)) => Result("found")
case (_, _, _) => Result("Not Found")
}
Also i don't know why you want to use map. It seems to me that this is not the proper tool for this job

Composing futures - how to get another variable associated with the result of a list of futures

I'm a bit new to future composition so I haven't figured out all the common patterns yet.
I have a list of futures but I need to associate a name with the futures when they are created so I can somehow reconcile the list.
EG if I create a list of futures like this, how can I get x to be associated with the future's result?
val requestsForMaster = shardNames.map { x ⇒
sentinel ? Request("SENTINEL", "get-master-addr-by-name", x)
}
I would do something like this to get the futures into a sequence
val mastersConfig = Future.sequence(requestsForMaster)
mastersConfig.onSuccess {
case x: List[Some[List[Some[ByteString]]]] ⇒
self ! x.map {
case Some(List(Some(host: ByteString), Some(port: ByteString))) ⇒
println("Host/port: " + host.utf8String + ":" + port.utf8String)
Shard("name", host.utf8String, port.utf8String.toInt, None)
}
}
But when I go to create the Shard object, the name (x) isn't available and I need it in there.
Any idea as to how I can compose these to get the name in there?
Edit:
Here is the solution I used:
val requestsForMaster = shardNames.map { x ⇒
(sentinel ? Request("SENTINEL", "get-master-addr-by-name", x)).map(y ⇒ (x, y))
}
val mastersConfig = Future.sequence(requestsForMaster)
mastersConfig.onSuccess {
case x: (List[(String, Some[List[Some[ByteString]]])]) ⇒
self ! x.map {
case (name, Some(List(Some(host: ByteString), Some(port: ByteString)))) ⇒
println("Name Host:port: " + name + " " + host.utf8String + ":" + port.utf8String)
Shard("name", host.utf8String, port.utf8String.toInt, None)
}
}
If I understand correctly, it sounds like you want to use map on the request futures to pair each response with the shard's name:
val requestsForMaster: List[Future[(String, Some[List[Some[ByteString]])] =
shardNames.map { x =>
val result = sentinel ? Request("SENTINEL", "get-master-addr-by-name", x)
result.map(x -> _)
}
val mastersConfig = Future.sequence(requestsForMaster)
mastersConfig.onSuccess {
case results: List[(String, Some[List[Some[ByteString]]])] =>
self ! results.map {
case (x, Some(List(Some(host: ByteString), Some(port: ByteString)))) =>
// Create the shard object.
}
}
More generally, if you have a Future[V] and a K, you can create a Future[(K, V)] by writing fv.map(k -> _).

Scala match case on regex directly

I am trying to do something like the following:
list.foreach {x =>
x match {
case """TEST: .*""" => println( "TEST" )
case """OXF.*""" => println("XXX")
case _ => println("NO MATCHING")
}
}
The idea is to use it like groovy switch case regex match. But I can't seem to get to to compile. Whats the right way to do it in scala?
You could either match on a precompiled regular expression (as in the first case below), or add an if
clause. Note that you typically don't want to recompile the same regular expression on each case evaluation, but rather have it on an object.
val list = List("Not a match", "TEST: yes", "OXFORD")
val testRegex = """TEST: .*""".r
list.foreach { x =>
x match {
case testRegex() => println( "TEST" )
case s if s.matches("""OXF.*""") => println("XXX")
case _ => println("NO MATCHING")
}
}
See more information here and some background here.
Starting Scala 2.13, it's possible to directly pattern match a String by unapplying a string interpolator:
// val examples = List("Not a match", "TEST: yes", "OXFORD")
examples.map {
case s"TEST: $x" => x
case s"OXF$x" => x
case _ => ""
}
// List[String] = List("", "yes", "ORD")

How do I pattern match arrays in Scala?

My method definition looks as follows
def processLine(tokens: Array[String]) = tokens match { // ...
Suppose I wish to know whether the second string is blank
case "" == tokens(1) => println("empty")
Does not compile. How do I go about doing this?
If you want to pattern match on the array to determine whether the second element is the empty string, you can do the following:
def processLine(tokens: Array[String]) = tokens match {
case Array(_, "", _*) => "second is empty"
case _ => "default"
}
The _* binds to any number of elements including none. This is similar to the following match on Lists, which is probably better known:
def processLine(tokens: List[String]) = tokens match {
case _ :: "" :: _ => "second is empty"
case _ => "default"
}
What is extra cool is that you can use an alias for the stuff matched by _* with something like
val lines: List[String] = List("Alice Bob Carol", "Bob Carol", "Carol Diane Alice")
lines foreach { line =>
line split "\\s+" match {
case Array(userName, friends#_*) => { /* Process user and his friends */ }
}
}
Pattern matching may not be the right choice for your example. You can simply do:
if( tokens(1) == "" ) {
println("empty")
}
Pattern matching is more approriate for cases like:
for( t <- tokens ) t match {
case "" => println( "Empty" )
case s => println( "Value: " + s )
}
which print something for each token.
Edit: if you want to check if there exist any token which is an empty string, you can also try:
if( tokens.exists( _ == "" ) ) {
println("Found empty token")
}
case statement doesn't work like that. That should be:
case _ if "" == tokens(1) => println("empty")

How to match a string on a prefix and get the rest?

I can write the code like this:
str match {
case s if s.startsWith("!!!") => s.stripPrefix("!!!")
case _ =>
}
But I want to know is there any better solutions. For example:
str match {
case "!!!" + rest => rest
case _ =>
}
val r = """^!!!(.*)""".r
val r(suffix) = "!!!rest of string"
So suffix will be populated with rest of string, or a scala.MatchError gets thrown.
A different variant would be:
val r = """^(!!!){0,1}(.*)""".r
val r(prefix,suffix) = ...
And prefix will either match the !!! or be null. e.g.
(prefix, suffix) match {
case(null, s) => "No prefix"
case _ => "Prefix"
}
The above is a little more complex than you might need, but it's worth looking at the power of Scala's regexp integration.
Starting Scala 2.13, it's now possible to pattern match a String by unapplying a string interpolator:
"!!!hello" match {
case s"!!!$rest" => rest
case _ => "oups"
}
// "hello"
If it's the sort of thing you do often, it's probably worth creating an extractor
object BangBangBangString{
def unapply(str:String):Option[String]= {
str match {
case s if s.startsWith("!!!") => Some(s.stripPrefix("!!!"))
case _ => None
}
}
}
Then you can use the extractor as follows
str match{
case BangBangBangString(rest) => println(rest)
case _ => println("Doesn't start with !!!")
}
or even
for(BangBangBangString(rest)<-myStringList){
println("rest")
}
Good question !
Even i was trying a lot to find out the answer.
Here is a good link where I found the answer
object _04MatchExpression_PatternGuards {
def main(args: Array[String]): Unit = {
val url: String = "Jan";
val monthType = url match {
case url if url.endsWith(".org") => "Educational Websites";
case url if url.endsWith(".com") => "Commercial Websites";
case url if url.endsWith(".co.in") => "Indian Websites"
case _ => "Unknow Input";
}
}
}