嵌套if else语句的替代方案- Scala

k2fxgqgv  于 7个月前  发布在  Scala
关注(0)|答案(3)|浏览(69)

我有多个if else和嵌套的if else语句。想知道有没有更好的方式来写这个?感谢你的指点。当前代码(if.else)在UDF中,将dataframe列作为输入来进行列值的条件检查(在该if else块中检查~5列)并返回true或false。
编辑:任何其他模式,如填充数据框中检查的条件,然后与数据框进行比较,其列在udf中检查,如Type,Flag 2,flag 3,flag,Fieldmdl等?

val retValue = 0
if (Type.startsWith("xyx "))
 {
   if (flag2 == 666) 
    { 
       
            if (flag3.toInt  <= 100) 
            {
                if (flag3  == 65) 
                {
                    retValue = 1
          
                }
                retValue = 0
            }
            else 
            {
               if ((flag3 == "200" && flag5 == "10") || (flag3 == "198" && flag5== "10") )
                  {
                     if ((Fieldmdl.Contains("fff")) || (Fieldmdl.Contains("ggg")) || (Fieldmdl.Contains("hhh")) || (Fieldmdl.Contains("ttt yyy")) 
                        ) 
                        {
                            retValue = 1                                    
                        }
                        else {
                            retValue = 0
                        }

                    }
                else 
                {
                   retValue = 1       
                }   
            }
        
      
    }

}

if (Type.startsWith("waq"))
{ 
       
        if (flag3.toInt < 123 ) 
        {
            retValue = 0
        }       
        if (flag3 == "ggg" && (Fieldmdl == "aaa" || Fieldmdl == "bcc"))
        {
            retValue = 0       
        }
                
           retValue = 1       
            
        }
 }

<If (type.startswith("dddd"?>
{
    check somethig and set the retvalue = 0 or 1
}
35g0bw71

35g0bw711#

你可以通过在Scala中使用模式匹配来简化嵌套的if-else语句:

def yourFunction(cols: YourColumnsType): Int = cols match {
  case _ if condition1 && condition2 && ... => 1
  case _ if anotherCondition => 0
  // More cases as needed
  case _ => 1 // Default case
}
cygmwpex

cygmwpex2#

除非你正在处理需要微优化的罕见用例(因为方法调用会导致几纳秒的速度减慢),否则使用描述性方法比多个嵌套的if-else更好。

if (condition1) handleCondition1()
else handleNotCondition1()

def handleCondition1(): Unit = {}

def handleNotCondition1(): Unit = 
  if (condition2) handleConition2()
  else handleNotCondition2()

def handleCondition2(): Unit = {}

def handleNotCondition2(): Unit = {}
yyhrrdl8

yyhrrdl83#

如果逻辑真的很简单,你应该尽可能通过expr列函数使用dsl或sql。Spark的内置功能可以明显更快,因为udf需要转换参数和返回值,并且不能与整个stage代码生成内联。
在Spark方面,你可以继续使用if,但你也可以使用case / when并嵌套它们(在一定程度上取决于Spark版本,任何超过64 k的代码生成都可以抛出)。这些Spark原生条件也受益于不断折叠或优化器重写。
基于更新后的代码示例,我注意到Scala的三个要点:
1.更喜欢Sash Sinha提到的匹配
1.你应该遵循Luis的指导,使用if作为表达式,不要操纵状态,在那里一个简单的表达式结果将工作。
1.使用实际的布尔类型。
你可以用一点红外线来匹配

class StartsWith(startsWith: String) {
  def unapply(arg: String): Option[(String)] =
    if (arg.startsWith(startsWith))
      Some(arg)
    else
      None
}

class Contains(contains: String) {
  def unapply(arg: String): Option[String] =
    if (arg contains contains)
      Some(contains)
    else
      None
}

object IsInt {
  def unapply(arg: String): Option[Int] =
    Try(arg.toInt).fold(_ => None, r => Some(r))
}

val xyx = new StartsWith("xyx ")
val waq = new StartsWith("waq")
val dddd = new StartsWith("dddd")

val contains_fff = new Contains("fff")
val contains_ggg = new Contains("ggg")
val contains_hhh = new Contains("hhh")
val contains_ttt_yyy = new Contains("ttt_yyy")

def theUDF(Type: String, flag2: Int, flag3: String, flag5: String, Fieldmdl: String): Boolean = {

  val retValue =
    (Type, flag2, flag3, flag5, Fieldmdl) match {
      case (xyx(_), 666, "65", _, _) => true
      case (xyx(_), 666, IsInt(f3), _, _) if f3 <= 100 => false
      case (xyx(_), 666, "200" | "198", "10",
        contains_fff(_) | contains_ggg(_) | contains_hhh(_) | contains_ttt_yyy(_) ) => true
      case (xyx(_), 666, "200" | "198", "10", _) => false
      case (xyx(_), 666, _, _, _) => true

      case (waq(_), _, IsInt(f3), _, _) if f3 < 123 => false
      case (waq(_), _, "ggg", "aaa" | "bcc", _) => false
      case (waq(_), _, _, _, _) => true

      case (dddd(_), _, _, _, _) => true

      case _ => false
    }

  retValue
}

assert(!theUDF("xyx ", 666, "200", "10", ""))
assert(theUDF("xyx ", 666, "200", "10", "hhh"))
assert(!theUDF("waq", 666, "ggg", "aaa", "hhh"))
assert(!theUDF("waq", 666, "2", "aaa", "hhh"))
assert(theUDF("waq", 666, "2000", "aa", "hhh"))
assert(theUDF("dddd", 666, "200", "10", "hhh"))

上面的StartsWith、Contains和IsInt不是必需的,但它使意图更清晰。
也就是说,你所拥有的大多数示例都非常适合Quality dq样式检查,你不会得到一个明确的if else,但你可以更容易地组织和审计所采取的路径,以及获得Spark内置优化。如果您真的需要“覆盖”结果,或者有多个udf,那么文件夹方法会很好地工作。
你可以根据sarveshseri的观点组织lambdas中的各种子if,以组合重用各种测试(即使你没有使用其他的Quality)。
只有当你计划经常改变这个if的规则,或者你确实添加了其他的if树udf时,这才真正有意义。

相关问题