[英]Scala: Convert procedural code to functional
I've written code similar to the one given below.我已经编写了类似于下面给出的代码。 It works as per the (bit confusing) requirements but something tells me it can be written differently in Scala using 'pattern matching' or something like that to make it look more functional .
它按照(有点令人困惑)要求工作,但有些东西告诉我它可以使用“模式匹配”或类似的东西在 Scala 中以不同的方式编写,以使其看起来更实用。 Any suggestions?
有什么建议?
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
}
As per the request here are some test cases:根据请求,这里有一些测试用例:
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")
First of all var
could be replaced with val
首先
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
}
Overall this huge if-else looks a bit complex.总的来说,这个巨大的 if-else 看起来有点复杂。 We can see there's only three possible results
buildXyz("a")
, buildXyz("b")
and None
So, this will look much better with just three if branches我们可以看到只有三个可能的结果
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
}
This will look even better with couple of helper methods:使用几个辅助方法看起来会更好:
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
}
}
And then java map could be converted to scala map.然后可以将 java 地图转换为 Scala 地图。 As we only care about counts we can map lists to sizes right away.
因为我们只关心计数,所以我们可以立即将列表映射到大小。 Then also change helpers to be more functional.
然后也将助手更改为更实用。
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
}
}
Your code, as posted, doesn't pass all your tests, but this does.您发布的代码并未通过所有测试,但确实通过了。
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")
}
The test suite:测试套件:
// 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.