需要帮助以函数式编程风格重构此 Scala 方法
Need help to refactor this scala method in functional programming style
我有这个 scala 方法可以根据一些参数构建地图:
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
?
一种方法包括不可变 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) }
}
另一种方法可以是
def foo(....) =
Map("name" -> name, "age" -> age, "hasChilds" -> hasChilds, "childs" -> childs)
.filter(_._2 != None).mapValues(_.get)
正如@Dider所指出的,这也可以做到,类似于@enzyme解决方案
Map("name" -> name, "age" -> age, "hasChilds" -> hasChilds, "childs" -> childs)
.collect {case (k, Some(v)) => (k,v) }
Scala 通常支持类型化数据和不变性,而您在这里反对这两者。我不知道这张地图的上下文是什么,但我认为使用带有可选参数的 case 类会更惯用。例如:
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 写成 case 的方法 class 可以防止这种情况,因为布尔方法取决于它要提供的信息的集合。
如果你真的坚持在这里使用地图,你可以使用 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 方法将其转换为不可变映射。
我有这个 scala 方法可以根据一些参数构建地图:
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
?
一种方法包括不可变 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) }
}
另一种方法可以是
def foo(....) =
Map("name" -> name, "age" -> age, "hasChilds" -> hasChilds, "childs" -> childs)
.filter(_._2 != None).mapValues(_.get)
正如@Dider所指出的,这也可以做到,类似于@enzyme解决方案
Map("name" -> name, "age" -> age, "hasChilds" -> hasChilds, "childs" -> childs)
.collect {case (k, Some(v)) => (k,v) }
Scala 通常支持类型化数据和不变性,而您在这里反对这两者。我不知道这张地图的上下文是什么,但我认为使用带有可选参数的 case 类会更惯用。例如:
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 写成 case 的方法 class 可以防止这种情况,因为布尔方法取决于它要提供的信息的集合。
如果你真的坚持在这里使用地图,你可以使用 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 方法将其转换为不可变映射。