假设有一个带有两个可选参数的函数代表两种不同的过滤条件。
def judge(a: Option[Int], b: Option[Int]) {
// here filter according the values of `a` and `b` if are set (not empty)
// if `a` or `b` is empty, then ignore.
// And if `a` and `b` both are empty, then filtering get nothing.
val objs: List[SomeObject] = ...
if (!(a.isEmpty) || !(b.isEmpty)) {
objs.filter { obj =>
a.map(_ == obj.a).getOrElse(true) && b.map(_ == obj.b).getOrElse(true)
}
} else {
List[SomeObject]()
}
}
看起来很有效,但我认为方式有点冗长。还有另一种更简单的方法吗?
答案 0 :(得分:2)
除了过滤器,一切看起来都不错。考虑:
objs filter { obj =>
( a.isEmpty || a.get == obj.a ) && ( b.isEmpty || b.get == obj.b )
}
在这些情况下,如果您希望“无”情况下的行为与“某些”案例的行为“混入”,则地图有点无用。
答案 1 :(得分:2)
我会做两处修改。
<强> 1 即可。 !(a.isEmpty) || !(b.isEmpty)
很难阅读,需要你(或至少我)仔细检查逻辑,以验证它实际上在做什么。
(a.nonEmpty || b.nonEmpty)
会更具表现力和逻辑等效。
<强> 2 即可。我认为在forall
中使用filter
会更加惯用。
例如:
a.forall(_ == obj.a)
与:
相同a.map(_ == obj.a).getOrElse(true)
我认为它的作用更清楚。对a
中包含的所有元素说,它们必须等于obj.a
。如果a
为空,那么默认情况下,它的所有元素都等于obj.a
(因为它没有任何元素,所以我们可以对它们说些什么,这将是真的)。
现在你的功能看起来更像是这样:
def judge(a: Option[Int], b: Option[Int]): List[SomeObject] = {
val objs = ...
if (a.nonEmpty || b.nonEmpty) {
objs.filter { obj =>
a.forall(_ == obj.a) && b.forall(_ == obj.b)
}
} else Nil
}
答案 2 :(得分:0)
您无需为列表中的每个对象反复测试每个参数是否为Some
- 您只需要执行一次。 map
执行测试的函数的每个参数,然后将flatten
这些参数放入过滤函数列表中。然后,如果有过滤器,reduce
将它们放入单个过滤器并将其应用于列表:
def judge(optA: Option[Int], optB: Option[Int]) = {
val foos = List(Foo(1,2), Foo(3,4))
val filters = List(
optA map (a => (foo: Foo) => foo.a == a),
optB map (b => (foo: Foo) => foo.b == b)
).flatten
if (filters.isEmpty) foos else foos filter filters.reduce{
(f1, f2) => (foo: Foo) => f1(foo) && f2(foo)
}
}
使用Vector
来保存对象可以通过显着减少分配的对象数量并避免在过滤reverse
后完成的隐式List
来提高性能。