我有一个Array [Float],我想使用该数组的元素初始化一个新对象。
以经典,必要的方式,我当然可以做到:
val array: Array[Float] = ...
val rect: Rect = new Rect(Point(array(0), array(1), Size(array(2), array(3))
有没有办法以更实用的方式使用某种类型的“地图”?像这样:
array => new Rect(Point(_(0), _(1)), Size(_(2), _(3)))
我正在尝试解析CSV文件:
string.split("\n") map {
line => line.split(".") map {
value => value.trim.toDouble
} => new Rect(Point(_(0), _(1)), Size(_(2), _(3))) // something like this?
}
答案 0 :(得分:2)
阵列的大小是否固定?您可以使用模式匹配:
.map { case Array(x, y, w, h) => new Rect(Point(x, y), Size(w, h)) }
示例:
scala> "1,2,3,4\n5,6,7,8".split("\n").map(_.split(",")).map { case Array(x,y,w,h) => (x,y,w,h) }
res3: Array[(String, String, String, String)] = Array((1,2,3,4), (5,6,7,8))
答案 1 :(得分:2)
不确定是否正常运行,但重复变量名称4次,如array(n)
可以通过解构来改善:
val Array(x, y, w, h) = "1,2,3,4".split(",").map(_.trim.toDouble)
new Rect(Point(x, y), Size(w, h))
(类似于Markus1189的答案,只是它不必是匿名函数)
我会说它更多是关于可读性而不是功能
答案 2 :(得分:1)
上述建议很好但容易出错,它使用了一个提取器,例如Scala添加的数组unnapply
。如果CSV文件已损坏,我看到的问题是获得MatchError
。
这种方法只会跳过文件中与条件不符的行,但如果您只想取前4行呢?
csv.lines.map {
case Array(x, y, w, h) => Some(new Rect(Point(x, y), Size(w, h)))
case _ => None
} flatten
如果你想简单地提取前四个变量,即使CSV行有超过4个元素,你也可以使用略有不同的语法,这就是说该行应该有“至少4个元素”
csv.lines.map {
case Array(x, y, w, h, _*) => Some(new Rect(Point(x, y), Size(w, h)))
case _ => None
} flatten
您甚至可以使用tail @ _*
语法获取对“其余元素”的引用。如果您希望对解析进行更细粒度的控制,并且有一些很好的错误报告:
val detailed: Array[Try[Rect]] = csv.lines.map {
case Array(x, y, w, h, tail @ _: *) => {
Success(new Rect(Point(x, y), Size(w, h)))
}
case arr @ _ => Failure(s"Entry had ${arr.size} elements, expected at least 4. ${arr.mkString(",")}")
}
为了更好地控制流量,我将map
逻辑分开为parseRow(input: Array[String]): Try[Rect]
。
def parseRow(input: Array[String]): Try[Rect] = input match {
case Array(x, y, w, h, tail @ _: *) => {
Success(new Rect(Point(x, y), Size(w, h)))
}
case arr @ _ => Failure(s"Entry had ${arr.size} elements, expected at least 4. ${arr.mkString(",")}")
}
您甚至可以考虑对您必须执行的任何转换进行更细粒度的处理,从实例从字符串输入转到Double
或Rect
需要的任何数学类型。
以下是我将使用的完整设置:
case class Point(x: Double, y: Double)
case class Size(x: Double, y: Double)
class Rect(val p: Point, val s: Size)
def parseDouble(input: String): Try[Double] = Try(input.toDouble)
def parseRow(input: Array[String]): Try[Rect] = input match {
case Array(x, y, w, h, tail @ _*) => {
for {
pointX <- parseDouble(x)
pointY <- parseDouble(y)
pointW <- parseDouble(w)
pointY <- parseDouble(y)
} yield {
new Rect(Point(pointX, pointY), Size(pointW, pointY))
}
}
case arr @ _ => Failure(new Exception(s"Entry had ${arr.length} elements, expected at least 4. ${arr.mkString(",")}"))
}
你可以很容易地重复使用上述内容:
val rects = csv.lines.map(parseRow)