2012-05-30 112 views
1

我正在研究一個有多個項目的3個可能結果的方法:錯誤,無效和成功。對於每一個我需要返回一個json列表來識別哪些項目出錯,無效並且成功。從flatMap返回多個集合

我目前的嘗試如下。我用Object來表示我的對象完全解釋的時間太長。該Object類有一個方法process當對象是無效的,它返回一個布爾值,以指示成功或錯誤並拋出異常:

def process(list: List[Objects]) = { 
    val successIds = new ListBuffer[Int](); 
    val errorIds = new ListBuffer[Int](); 
    val invalidIds = new ListBuffer[Int](); 

    list.foreach(item => { 
     try { 
      if (item.process) { 
       successIds ++ item.id 
      } else { 
       errorIds ++ item.id 
      } 
     } catch { 
      case e: Exception => invalidIds ++ item.id 
     } 
    }) 

    JsonResult(
     Map("success" -> successIds, 
      "failed" -> errorIds, 
      "invalid" -> invalidIds) 
    ) 
} 

問題是使用可變的數據結構不是很「的Scala-Y」。我更願意以更實用的方式構建這些列表,但我對scala很陌生。任何想法或提示如何做到這一點?

我雖然是使用類似的flatMap方法,它收集的元組並整理他們以同樣的方式在flatMap方法確實爲一個集合:

def process(list: List[Objects]) = { 

    val (success, error, invalid) = list.flatMap(item => { 
     try { 
      if (item.process) { 
       (List(item.id), List.empty, List.empty) 
      } else { 
       (List.empty, List(item.id), List.empty) 
      } 
     } catch { 
      case e: Exception => 
       (List.empty, List.empty, List(item.id)) 
     } 
    }) 

    JsonResult(
     Map("success" -> success, 
      "failed" -> error, 
      "invalid" -> invalid) 
    ) 
} 
+0

看看這個要點解釋使用應用仿函數進行非故障快速驗證,由ScalaZ提供:https://gist.github.com/970717 – opyate

回答

8

flatMap是不是你所需要的是什麼 - 你需要groupBy

def process(list: List[Objects]) = { 

    def result(x: Objects) = 
    try if (x.process) "success" else "failed" 
    catch {case _ => "invalid"}  

    JsonResult(list groupBy result mapValues (_ map (_.id))) 
} 
+0

+1 - 對於這個特定的問題肯定比我的答案更好! –

+0

+1,「試試如果...其他...」,這種語言不能做什麼? – virtualeyes

+0

花了我一段時間才真正實現這一點,抱歉。做得很好,簡單和簡潔的+1 –

1

總是有遞歸:

class Ob(val id: Int) { def okay: Boolean = id < 5 } 


@annotation.tailrec def process(
    xs: List[Ob], 
    succ: List[Int] = Nil, 
    fail: List[Int] = Nil, 
    invalid: List[Int] = Nil 
): (List[Int], List[Int], List[Int]) = xs match { 
    case Nil => (succ.reverse, fail.reverse, invalid.reverse) 
    case x :: more => 
    val maybeOkay = try { Some(x.okay) } catch { case e: Exception => None } 
    if (!maybeOkay.isDefined) process(more, succ, fail, x.id :: invalid) 
    else if (maybeOkay.get) process(more, x.id :: succ, fail, invalid) 
    else      process(more, succ, x.id :: fail, invalid) 
} 

其中一期工程爲人們希望(跳過挫折,如果你不關心順序):

scala> process(List(new Ob(1), new Ob(7), new Ob(2), 
    new Ob(4) { override def okay = throw new Exception("Broken") })) 

res2: (List[Int], List[Int], List[Int]) = (List(1,2),List(7),List(4)) 
0

改編,使其編譯不「對象」

def procex (item: String): Boolean = ((9/item.toInt) < 1) 

def process (list: List[String]) = { 
    val li: List[(Option[String], Option[String], Option[String])] = list.map (item => { 
     try { 
      if (procex (item)) { 
       (Some (item), None, None) 
      } else { 
       (None, Some (item), None) 
      } 
     } catch { 
      case e: Exception => 
       (None, None, Some (item)) 
     } 
    }) 
    li 
} 
// below 10 => failure 
val in = (5 to 15).map (""+_).toList 
// 0 to throw a little exception 
val ps = process ("0" :: in) 

val succeeders = ps.filter (p=> p._1 != None).map (p=>p._1) 
val errors  = ps.filter (p=> p._2 != None).map (p=>p._2) 
val invalides = ps.filter (p=> p._3 != None).map (p=>p._3) 

什麼不起作用:

(1 to 3).map (i=> ps.filter (p=> p._i != None).map (p=>p._i)) 

_i不起作用。