2017-01-23 88 views
1

這是一種美容斯卡拉問題。對象列表需要根據對象的屬性進行過濾。如果對屬性的第一次檢查導致列表爲空,我需要報告。簡化代碼:過濾器和報告多謂詞

case class Account (id: Int, balance: Float) 

def doFilter(list: List[Account], focusId: Int, thresHold: Float): List[Account] = { 
    list.filter(_.id == focusId) 
    // ## if at this point if the list is empty, an error log is required. 
    .filter(_.balance >= thresHold) 
} 

var accounts = List(Account(1, 5.0f), Account(2, -1.0f), Account(3, 10f), Account(4, 12f)) 

println(s"result ${doFilter(accounts, 1, 0f)}") 

我當然可以拆分過濾語句,檢查中間結果,但我希望我能做到這一點更斯卡拉方式..我想是這樣。

list.filter(_.id == focusId) 
match { case List() => { println "error"; List()} 
case _ => _} 

但這並不奏效。是否有功能(或流利)的方式來實現所需的行爲?

回答

2

下面的代碼是從輕微的修改this SO answer from Rex Kerr

implicit class KestrelPattern[A](private val repr: A) extends AnyVal { 
    def tee[B](f: A => B) = { f(repr); repr } // B is thrown away (Unit) 
} 

他稱之爲tap。我選擇了tee,因爲它與unix tee命令相似。

用法:

scala> List[Int](3,5,7).tee{x => if (x.isEmpty) println("ERROR")}.sum 
res42: Int = 15 

scala> List[Int]().tee{x => if (x.isEmpty) println("ERROR")}.sum 
ERROR 
res43: Int = 0 
2

如果您需要一次,那麼記錄中間結果可能是最簡單的方法。如果您需要這在幾個地方,你可以使代碼更好一點使用擴展方法:

implicit class ListOps[+A](val list: List[A]) extends AnyVal { 
    def logIfEmpty(): List[A] = { 
     if (list.isEmpty) { 
     println("Error: empty list") 
     // or whatever; you can even pass it as an argument 
    } 
    list 
    } 
} 

然後你可以使用它像這樣:

def doFilter(list: List[Account], focusId: Int, thresHold: Float): List[Account] = list 
    .filter(_.id == focusId) 
    .logIfEmpty() 
    .filter(_.balance >= thresHold) 
1

配套工程的模式,你的代碼的錯誤來自於事實,你正試圖在第二種情況下返回_,你可能要檢查herehere爲什麼這個可能是一個問題:

accounts.filter(_.id == 1) match { 
     case List() => { println("error"); List() } 
     case x => x.filter(_.balance > 1.0) 
} 
// res19: List[Account] = List(Account(1,5.0)) 


accounts.filter(_.id == 5) match { 
     case List() => { println("error"); List() } 
     case x => x.filter(_.balance > 1.0) 
} 
// error 
// res20: List[Account] = List()