在每个条目产生0或1个结果的集合上调用map的惯用方法是什么?
假设我有:
val data = Array("A", "x:y", "d:e")
我想要的结果是:
val target = Array(("x", "y"), ("d", "e"))
(删除任何没有冒号的东西,在冒号上拆分并返回元组)
所以理论上我觉得我想做点什么:
val attempt1 = data.map( arg => {
arg.split(":", 2) match {
case Array(l,r) => (l, r)
case _ => (None, None)
}
}).filter( _._1 != None )
我想做的是避免任何案件的需要并摆脱filter
。
我可以通过预过滤来做到这一点(但后来我必须测试两次正则表达式):
val attempt2 = data.filter( arg.contains(":") ).map( arg => {
val Array(l,r) = arg.split(":", 2)
(l,r)
})
最后,我可以使用Some / None和flatMap ...这确实摆脱了filter
的需要,但这是大多数scala程序员所期望的吗?
val attempt3 = data.flatMap( arg => {
arg.split(":", 2) match {
case Array(l,r) => Some((l,r))
case _ => None
}
})
在我看来,在Scala中有这样一种惯用的方式,是吗?
答案 0 :(得分:12)
使用Regex
提取器和collect
: - )
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))
修改强>
如果你想要一张地图,你可以这样做:
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)
如果需要考虑性能,可以使用collection.breakOut
,如下所示,以避免创建中间数组:
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)