What is the idiomatic way of matching producing 0 or 1 result per record?

What is the idiomatic way to name a card by a collection producing 0 or 1 result per record?

Suppose I have:

val data = Array("A", "x:y", "d:e") 

As a result, I would like to:

 val target = Array(("x", "y"), ("d", "e")) 

(discard everything without a colon, divide by colon and return tuples)

So in theory, I think I want to do something like:

 val attempt1 = data.map( arg => { arg.split(":", 2) match { case Array(l,r) => (l, r) case _ => (None, None) } }).filter( _._1 != None ) 

What I would like to do is to avoid the need anyway and get rid of the filter .

I could do this with pre-filtering (but then I need to double-check the regex):

 val attempt2 = data.filter( arg.contains(":") ).map( arg => { val Array(l,r) = arg.split(":", 2) (l,r) }) 

Finally, I could use Some / None and flatMap ..., which eliminates the need for a filter , but is this what most scala programmers would expect?

 val attempt3 = data.flatMap( arg => { arg.split(":", 2) match { case Array(l,r) => Some((l,r)) case _ => None } }) 

It seems to me that there is an idiomatic way to do this in Scala?

+4
source share
1 answer

Using the Regex and collect extractor Regex

 scala> val R = "(.+):(.+)".r R: scala.util.matching.Regex = (.+):(.+) scala> Array("A", "x:y", "d:e") collect { | case R(a, b) => (a, b) | } res0: Array[(String, String)] = Array((x,y), (d,e)) 

Edit:

If you want to get a card, you can do:

 scala> val x: Map[String, String] = Array("A", "x:y", "d:e").collect { case R(a, b) => (a, b) }.toMap x: Map[String,String] = Map(x -> y, d -> e) 

If performance is a problem, you can use collection.breakOut as shown below to avoid creating an intermediate array:

 scala> val x: Map[String, String] = Array("A", "x:y", "d:e").collect { case R(a, b) => (a, b) } (collection.breakOut) x: Map[String,String] = Map(x -> y, d -> e) 
+12
source

Source: https://habr.com/ru/post/1479810/


All Articles