2016-10-04 57 views
1

我有一個業務規則列表,並且多個規則可以應用於給定的輸入。如何在Seq上進行過濾[部分功能]

type Input = … 
type Output = … 
type Rule = PartialFunction[Input, Output] 

我想編寫計算所有有效輸出的方法。我想出了這個實現:

def applyRules(i: Input, rules: Seq[Rule]) : Seq[Output] = { 
    rules.flatMap(_.lift.apply(i)) 
} 

有沒有更好的方法?

+0

是的,我就是這麼做的。作爲選項,您不需要拼寫出'apply' btw: 'rules.flatMap(_。lift(i))' – Dima

+0

'rules.flatMap(Seq(i).collect(_))'' rules.flatMap(Some(i).collect(_))'(儘管我不喜歡'CanBuildFrom'魔術) –

回答

-1

您可以使用isDefinedAt檢查是否給出可應用於InputRule

scala> val pf: PartialFunction[Any, Int] = { case s: String => 42 } 
pf: PartialFunction[Any,Int] = <function1> 

scala> pf.isDefinedAt(10) 
res0: Boolean = false 

scala> pf.isDefinedAt("") 
res1: Boolean = true 

所以,你可以這樣做:

val validInputs = rules.filter(_.isDefinedAt(i)) 
val result = validInputs.map(i) 

而且PartialFunction包含的方法applyOrElse, orElse, ...,這可能增加可讀性。

如果我誤解了您的問題,請糾正我。

+0

Op的解決方案更好 – Dima

0

您的解決方案的一個建議變體(我認爲是令人滿意的)涉及過濾,然後映射過濾結果。這種方法很有效,但是涉及兩個通過相同的收集,對於較小的收集可以是好的。

  1. 使用collect方法:rules.collect { case r if r.isDefinedAt(i) => r(i) }
  2. 使用的懶惰withFilter代替filter:使用for理解rules.withFilter(_.isDefinedAt(i)).map(_.apply(i))
  3. (語義上相同我們可以,但是,有三個可能的進一步的變體達到相同的結果到所述一個以上但也許更可讀的):for (r <- rule if r isDefinedAt i) r(i)

這些解決方案可能產生的垃圾會少一些(每次調用lift都會創建一個函數對象的新實例 - here,code),但是如果規則的數量很少,我相信在大多數情況下這不是問題。