需要帮助在函数式编程风格中重构这个scala方法

时间:2015-01-16 17:37:36

标签: scala functional-programming

我有这个scala方法,可以从一些参数构建Map:

def foo(name: Option[String], age: Option[Int], hasChilds: Option[Boolean], 
    childs: Option[List[Map[String, Any]]]): Map[String,Any] = {

    var m = Map[String, Any]()

    if (!name.isEmpty) m += ("name" -> name.get)
    if (!age.isEmpty) m += ("age" -> age.get)
    if (!hasChilds.isEmpty) m += ("hasChilds" -> hasChilds.get)
    if (!childs.isEmpty) m += ("childs" -> childs.get)

    m
}

我想知道是否有办法以更多功能的方式重构代码?

在这种情况下是否可以使用var

3 个答案:

答案 0 :(得分:6)

一种方法包括扁平化不可变Map,像这样,

def foo(name: Option[String], 
        age: Option[Int], 
        hasChilds: Option[Boolean], 
        childs: Option[List[Map[String, Any]]]): Map[String,Any] = {

  Map( ("name" -> name), 
       ("age" -> age),
       ("hasChilds" -> hasChilds),  
       ("childs" -> childs)).collect { case(a,Some(b)) => (a,b) }
}

答案 1 :(得分:2)

另一种方法可以是

def foo(....) = 
   Map("name" -> name, "age" -> age, "hasChilds" -> hasChilds, "childs" ->  childs)
.filter(_._2 != None).mapValues(_.get)

正如@Dider所指出的,这也可以做,类似于@enzyme solution

Map("name" -> name, "age" -> age, "hasChilds" -> hasChilds, "childs" -> childs)
.collect {case (k, Some(v)) => (k,v) }

答案 2 :(得分:0)

Scala通常支持键入的数据和不变性,并且您正在与这两者进行斗争。我不知道这张地图的背景是什么,但我认为使用带有可选参数的case clase会更加惯用。例如:

case class Person(name: String, age: Option[Int], children: Seq[Person]) {
  def hasChildren: Boolean = !children.isEmpty
}

现在您可以使用可选的名称变量调用此方法。

val name: Option[String] = Option("suud")
val age: Option[Int] = Option(25)
val children: Seq[Person] = Seq.empty
val suud: Option[Person] = name map {Person(_, age, children)}

写入foo的方式,可以传入一个空的子列表,其中包含一个布尔参数,表示该地图有子项。编写hasChildren作为案例类的方法可以防止这种情况,因为布尔方法依赖于它所提供的有关信息的集合。

如果你真的坚持在这里使用地图,你可以使用MapBuilder来获取不可变的地图,或者只是导入并使用可变地图。

import scala.collection.mutable.MapBuilder

val builder: MapBuilder[String, Any, Map[String, Any]] = new MapBuilder(Map.empty)

if (!name.isEmpty) builder += ("name" -> name.get)
if (!age.isEmpty) builder += ("age" -> age.get)
if (!hasChilds.isEmpty) builder += ("hasChilds" -> hasChilds.get)
if (!childs.isEmpty) builder += ("childs" -> childs.get)

builder.result

现在构建器的结果是一个不可变的映射。如果你真的需要一个可变的地图,你可以:

import scala.collection.mutable

val m = mutable.Map[String, Any]()

现在您已经拥有了一个可变映射,可以使用toMap方法将其转换为不可变映射。