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

问题描述

我编写了类似于以下代码代码。它可以按照(位混乱)的要求工作,但是有人告诉我可以使用“模式匹配”或类似的方法在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,所以如果只有三个if分支,这看起来会更好

  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),"d" -> List.fill(11)(new SomeObject)))
//This should return Some(XyzObject("a"))

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...