繁体   English   中英

Scala:将程序代码转换为功能代码

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM