![](/img/trans.png)
[英]How do I make the following Scala code more functional and less procedural?
[英]Scala: Convert procedural code to functional
我已经编写了类似于下面给出的代码。 它按照(有点令人困惑)要求工作,但有些东西告诉我它可以使用“模式匹配”或类似的东西在 Scala 中以不同的方式编写,以使其看起来更实用。 有什么建议?
def xyzMethod(map: util.HashMap[Any, List[SomeObject]]) : Option[xyzObject] = {
var myObject: Option[xyzObject] = None
val cCount: Int = map.get("c").size
if (cCount != 10) {
val bCount: Int = map.get("b").size
if (bCount + cCount == 20) {
myObject = buildXyz("b")
} else {
val aCount: Int = map.get("a").size
if (aCount != 0) {
val dCount: Int = map.get("d").size
if (dCount > 10) {
myObject = buildXyz("a")
}
}
}
}
myObject
}
根据请求,这里有一些测试用例:
Test Case 1:
map =>
"c" => Objectc1, Objectc2... Objectc10
This should return None
-----------
Test Case 2:
map =>
"c" => Objectc1, Objectc2
"b" => Objectb1, Objectb2..... Objectb18
This should return buildXyz("b")
-----------
Test Case 3:
map =>
"c" => Objectc1
"b" => Objectb1, Objectb2
This should return None
-----------
Test Case 4:
map =>
"c" => Objectc1
"b" => Objectb1, Objectb2
"a" => Objecta1
"d" => Objectd1
This should return None
-----------
Test Case 5:
map =>
"c" => Objectc1
"b" => Objectb1, Objectb2
"a" => Objecta1
"d" => Objectd1, Objectd2......Objectd10, Objectd11
This should return buildXyz("a")
首先var
可以替换为val
def xyzMethod1(map: java.util.HashMap[Any, List[SomeObject]]): Option[xyzObject] = {
val cCount: Int = map.get("c").size
val myObject: Option[xyzObject] = if (cCount != 10) {
val bCount: Int = map.get("b").size
if (bCount + cCount == 20) {
buildXyz("b")
} else {
val aCount: Int = map.get("a").size
if (aCount != 0) {
val dCount: Int = map.get("d").size
if (dCount > 10) {
buildXyz("a")
} else {
None
}
} else {
None
}
}
} else {
None
}
myObject
}
总的来说,这个巨大的 if-else 看起来有点复杂。 我们可以看到只有三个可能的结果buildXyz("a")
、 buildXyz("b")
和None
所以,如果分支只有三个,这看起来会好得多
def xyzMethod1(map: java.util.HashMap[Any, List[SomeObject]]): Option[xyzObject] = {
val aCount: Int = map.get("a").size
val bCount: Int = map.get("b").size
val cCount: Int = map.get("c").size
val dCount: Int = map.get("d").size
val myObject: Option[xyzObject] = if (cCount != 10 && bCount + cCount == 20) {
buildXyz("b")
} else if (cCount != 10 && aCount != 0 && dCount > 10) {
buildXyz("a")
} else {
None
}
myObject
}
使用几个辅助方法看起来会更好:
def isBuildA(map: java.util.HashMap[Any, List[SomeObject]]): Boolean = {
val aCount: Int = map.get("a").size
val cCount: Int = map.get("c").size
val dCount: Int = map.get("d").size
cCount != 10 && aCount != 0 && dCount > 10
}
def isBuildB(map: java.util.HashMap[Any, List[SomeObject]]): Boolean = {
val bCount: Int = map.get("b").size
val cCount: Int = map.get("c").size
cCount != 10 && bCount + cCount == 20
}
def xyzMethod1(map: java.util.HashMap[Any, List[SomeObject]]): Option[xyzObject] = {
if (isBuildA(map)) {
buildXyz("a")
} else if (isBuildB(map)) {
buildXyz("b")
} else {
None
}
}
然后可以将 java 地图转换为 Scala 地图。 因为我们只关心计数,所以我们可以立即将列表映射到大小。 然后也将助手更改为更实用。
def isBuildA(map: scala.collection.Map[Any, Int]): Boolean = {
map.exists(v => v._1 == "c" && v._2 != 10) &&
map.exists(v => v._1 == "a" && v._2 != 0) &&
map.exists(v => v._1 == "d" && v._2 > 10)
}
def isBuildB(map: scala.collection.Map[Any, Int]): Boolean = {
map.exists(v => v._1 == "c" && v._2 != 10) &&
map.filterKeys(k => k == "b" || k == "c").values.sum == 20
}
def xyzMethod1(map: java.util.HashMap[Any, List[SomeObject]]): Option[xyzObject] = {
import scala.collection.JavaConverters._
val map1 = map.asScala.mapValues(_.size)
if (isBuildA(map1)) {
buildXyz("a")
} else if (isBuildB(map1)) {
buildXyz("b")
} else {
None
}
}
您发布的代码并未通过所有测试,但确实通过了。
import scala.collection.immutable.HashMap
//just enough stubs to make everything compile
case class XyzObject(x:String)
class SomeObject
def buildXyz(xyz:String) = Option(XyzObject(xyz))
def xyzMethod(map: HashMap[Any, List[SomeObject]]) :Option[XyzObject] = {
val cCount: Int = map.getOrElse("c", Nil).size
if (cCount == 10) None
else if (map.getOrElse("b",Nil).size + cCount == 20) buildXyz("b")
else if (map.getOrElse("a",Nil).isEmpty ||
map.getOrElse("d",Nil).size < 11) None
else buildXyz("a")
}
测试套件:
// Test Case 1:
xyzMethod(HashMap("c" -> List.fill(10)(new SomeObject)))
//This should return None
//Test Case 2:
xyzMethod(HashMap("c" -> List.fill(2)(new SomeObject)
,"b" -> List.fill(18)(new SomeObject)))
//This should return Some(XyzObject("b"))
//Test Case 3:
xyzMethod(HashMap("c" -> List.fill(1)(new SomeObject)
,"b" -> List.fill(2)(new SomeObject)))
//This should return None
//Test Case 4:
xyzMethod(HashMap("c" -> List.fill(1)(new SomeObject)
,"b" -> List.fill(2)(new SomeObject)
,"a" -> List.fill(1)(new SomeObject)
,"d" -> List.fill(1)(new SomeObject)))
//This should return None
//Test Case 5:
xyzMethod(HashMap("c" -> List.fill(1)(new SomeObject)
,"b" -> List.fill(2)(new SomeObject)
,"a" -> List.fill(1)(new SomeObject)
,"d" -> List.fill(11)(new SomeObject)))
//This should return Some(XyzObject("a"))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.