假设我想有条件地建立比萨的成分列表:
val ingredients = scala.collection.mutable.ArrayBuffer("tomatoes", "cheese")
if (!isVegetarian()) {
ingredients += "Pepperoni"
}
if (shouldBeSpicy()) {
ingredients += "Jalapeno"
}
//etc
是否有使用不可变集合构建此数组的功能方法?
我想到了:
val ingredients = List("tomatoes", "cheese") ++ List(
if (!isVegetarian()) Some("Pepperoni") else None,
if (shouldBeSpicy()) Some("Jalapeno") else None
).flatten
但有更好的方法吗?
答案 0 :(得分:2)
这是另一种可能更接近@Antot的方式,但恕我直言更简单。
原始代码中不清楚的是isVegetarian
和shouldBeSpicy
实际来自哪里。在这里,我假设有一个PizzaConf
类来提供这些配置设置
case class PizzaConf(isVegetarian: Boolean, shouldBeSpicy: Boolean)
假设这一点,我认为最简单的方法是使用allIngredients
List[(String, Function1[PizzaConf, Boolean])]
类型,即存储成分和功能以检查其相应可用性的类型。鉴于buildIngredients
变得微不足道:
val allIngredients: List[(String, Function1[PizzaConf, Boolean])] = List(
("Pepperoni", conf => conf.isVegetarian),
("Jalapeno", conf => conf.shouldBeSpicy)
)
def buildIngredients(pizzaConf: PizzaConf): List[String] = {
allIngredients
.filter(_._2(pizzaConf))
.map(_._1)
}
或者您可以使用filter
合并map
和collect
,如下所示:
def buildIngredients(pizzaConf: PizzaConf): List[String] =
allIngredients.collect({ case (ing, cond) if cond(pizzaConf) => ing })
答案 1 :(得分:1)
您可以从完整的成分列表开始,然后过滤掉不符合条件的成分:
Set("tomatoes", "cheese", "Pepperoni", "Jalapeno")
.filter {
case "Pepperoni" => !isVegetarian;
case "Jalapeno" => shouldBeSpicy;
case _ => true // ingredients by default
}
用于:
val isVegetarian = true
val shouldBeSpicy = true
将返回:
Set(tomatoes, cheese, Jalapeno)
答案 2 :(得分:1)
这可以通过创建一个谓词序列来实现,该序列定义了用于过滤成分的条件。
second
`111`,`222`,`333`,`444`,`555`
答案 3 :(得分:1)
如果任何成分只需要针对一种情况进行测试,您可以这样做:
val commonIngredients = List("Cheese", "Tomatoes")
val nonVegetarianIngredientsWanted = {
if (!isVegetarian)
List("Pepperoni")
else
List.empty
}
val spicyIngredientsWanted = {
if (shouldBeSpicy)
List("Jalapeno")
else
List.empty
}
val pizzaIngredients = commonIngredients ++ nonVegetarianIngredientsWanted ++ spicyIngredientsWanted
如果您的成分经过两个类别的测试,这不起作用:例如,如果你有辣香肠,那么只有在!是素食和辣味成分的情况下才应该包括。这样做的一种方法是同时测试两种情况:
val (optionalIngredients) = {
(nonVegetarianIngredientsWanted, spicyIngredientsWanted) match {
case (false, false) => List.empty
case (false, true) => List("Jalapeno")
case (true, false) => List("Pepperoni")
case (true, true) => List("Pepperoni, Jalapeno, Spicy Sausage")
}
val pizzaIngredients = commonIngredients ++ optionalIngredients
这可以扩展到测试任何数量的条件,当然所需的案例臂数量随着测试条件的数量呈指数级增长。
答案 4 :(得分:1)
你原来的做法还不错。我可能会坚持使用list:
val ingredients =
List("tomatoes", "cheese") ++
List("Pepperoni", "Sausage").filter(_ => !isVegetarian) ++
List("Jalapeno").filter(_ => shouldBeSpicy)
这样可以轻松添加与条件相关的更多成分(参见" Sausage"上面)
答案 5 :(得分:0)
受到其他答案的启发,我想出了类似的东西:
case class If[T](conditions: (Boolean, T)*) {
def andAlways(values: T*): List[T] =
conditions.filter(_._1).map(_._2).toList ++ values
}
可以像:
一样使用val isVegetarian = false
val shouldBeSpicy = true
val ingredients = If(
!isVegetarian -> "Pepperoni",
shouldBeSpicy -> "Jalapeno",
).andAlways(
"Cheese",
"Tomatoes"
)
仍在等待更好的选择:)