简体   繁体   English

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

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

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