我正在使用下面的代码,我正在寻找一些想法来进行一些优化。
analyzePayload:
输入:有效负载,即JsObject和规则列表,每个规则都有几个条件。
输出:在此特定负载上成功、notApplicable或失败的所有规则的 MyReport。
列表的大小可以是相当大的,而且每个规则都有大量的条件。
我正在寻找一些关于如何优化代码的想法,也许是用一个懒惰的集合?视野?溪流?裁缝?为什么-谢谢!
另外,请注意,我有anaylzeMode,它只能在一条规则对ex成功之前才能运行。
def analyzePayload(payload: JsObject, rules: List[Rule]): MyReport = {
val analyzeMode = appConfig.analyzeMode
val (succeed, notApplicable, failed) = rules.foldLeft((List[Rule](), List[Rule](), List[Rule]())) { case ( seed @ (succeedRules,notApplicableRules,failedRules), currRule) =>
// Evaluate Single Rule
def step(): (List[Rule], List[Rule], List[Rule]) = evalService.eval(currRule, payload) match {
// If the result is succeed
case EvalResult(true, _, _) => (currRule :: succeedRules, notApplicableRules, failedRules)
// If the result is notApplicable
case EvalResult(_, missing @ _ :: _, _) => (succeedRules, currRule :: notApplicableRules, failedRules
)
// If the result is unmatched
case EvalResult(_, _, unmatched @ _ :: _) => (succeedRules, notApplicableRules, currRule :: failedRules)
}
analyzeMode match {
case UNTIL_FIRST_SUCCEED => if(succeedRules.isEmpty) step() else seed
case UNTIL_FIRST_NOT_APPLICABLE => if(notApplicableRules.isEmpty) step() else seed
case UNTIL_FIRST_FAILED => if(failedRules.isEmpty) step() else seed
case DEFAULT => step()
case _ => throw new IllegalArgumentException(s"Unknown mode = ${analyzeMode}")
}
}
MyReport(succeed.reverse, notApplicable.reverse, failed.reverse)
}第一编辑:修改了代码以使用tailrec,从@Tim,还有其他建议吗?或者一些让代码更漂亮的建议?另外,我想问一下,在前面的实现中,在view之前使用foldLeft是否有什么不同。也可以使用其他集合,如ListBuffer或Vector。
def analyzePayload(payload: JsObject, actionRules: List[ActionRule]): MyReport = {
val analyzeMode = appConfig.analyzeMode
def isCompleted(succeed: List[Rule], notApplicable: List[Rule], failed: List[Rule]) = ((succeed, notApplicable, failed), analyzeMode) match {
case (( _ :: _, _, _), UNTIL_FIRST_SUCCEED) | (( _,_ :: _, _), UNTIL_FIRST_NOT_APPLICABLE) | (( _, _, _ :: _), UNTIL_FIRST_FAILED) => true
case (_, DEFAULT) => false
case _ => throw new IllegalArgumentException(s"Unknown mode on analyzePayload with mode = ${analyzeMode}")
}
@tailrec
def _analyzePayload(actionRules: List[ActionRule])(succeed: List[Rule], notApplicable: List[Rule], failed: List[Rule]): (List[Rule], List[Rule] ,List[Rule]) = actionRules match {
case Nil | _ if isCompleted(succeed, notApplicable, failed) => (succeed, notApplicable, failed)
case actionRule :: tail => actionRuleService.eval(actionRule, payload) match {
// If the result is succeed
case EvalResult(true, _, _) => _analyzePayload(tail)(actionRule :: succeed, notApplicable, failed)
// If the result is notApplicable
case EvalResult(_, missing @ _ :: _, _) => _analyzePayload(tail)(succeed, actionRule :: notApplicable, failed)
// If the result is unmatched
case EvalResult(_, _, unmatched @ _ :: _) => _analyzePayload(tail)(succeed, notApplicable, actionRule :: failed)
}
}
val res = _analyzePayload(actionRules)(Nil,Nil,Nil)
MyReport(res._1, res._2, res._3)
}编辑2:(问题)
如果有结果,
view,这样做没有意义吗?既然所有的数据都将被评估,对吗?,
ParSeq来代替?或者这只是慢一点,因为evalService.eval(...)的操作不是一个繁重的操作??发布于 2021-01-22 11:10:31
有两个明显的优化:
使用尾递归函数评价器而不是foldLeft,这样编译器就可以生成一个优化的循环,并在找到合适的规则后立即终止。
由于analyzeMode是常量,所以将match取到foldLeft之外。或者为每种模式都有单独的代码路径,或者使用analyzeMode来选择循环中使用的函数来检查是否终止。
发布于 2021-01-22 12:10:08
代码很好,重温的主要内容是让evalService.eval在json对象的单个遍历中计算多条规则,前提是json的大小不可忽略。
https://stackoverflow.com/questions/65842837
复制相似问题