2012-09-13 40 views
2

林在斯卡拉一個初學者,正在尋找最好的/慣用的方式做什麼,我打算在這裏做。斯卡拉一成不變的列表添加一個「單位」元素

這就是我想要做的

def someMethod(obj:MyObj):List[String] = { 
    List[String]() +: 
     {if (somecondition is satisfied) .. " element"} +: 
     { if (another condition) .. " something else " } 


} 

也就是說該方法檢查輸入參數對象的某些屬性和元素添加到列表(也就是要返回)。如果沒有條件滿足,它應該返回一個空列表。

  1. 當然代碼不會編譯。但不知何故,我覺得List [T] + Unit應該返回List [T],這似乎很直觀。爲什麼我錯了?

和2.請告訴我正確的方式來做到這一點斯卡拉。如果我正在迭代一系列條件,我可以使用解析。

回答

2

你可以寫這樣的:

def someMethod(obj:MyObj):List[String] = { 
    List(
     if (somecondition is satisfied) " element", 
     if (another condition) " something else " 
    ) collect{ case x: String => x } 
} 

假設所有條件都失敗了:你會擁有List(Unit,Unit)第一,這將是按類型過濾。單元不滿足收集的類型條件,所以結果將是空的字符串列表

好的是,不像filter方法collect選擇儘可能緊的類型(所以你會得到序列的字符串 - 這將從功能內收集)。

另一種可能性是用flatten替換.collect { ... },但是會丟失類型信息。

+0

謝謝..這個工程。 – questionersam

+0

你能解釋一下這段代碼的工作原理嗎?特別是我不知道是什麼'..'確實在斯卡拉... – ziggystar

+0

@ziggystar沒有魔法在這裏,在斯卡拉'..'沒什麼,我剛剛從op片段中複製了一些代碼,我想他不想說這是公正的。我已經添加了有關事情如何工作和刪除的詳細信息,以消除混淆。 –

3

if - else是Scala的表達式。你寫的是:

List[String]() +: 
     {if (somecondition is satisfied) {" element";() } else() }+: 
     { if (another condition) { " something else ";() } else() } 

正如你所看到的,常見的分支類型是Unit

類型整個表達式將是List[Any]因爲這是的StringUnit公共超類型。

一些方法來達到你想要什麼:

// #1. Ugly. 
def someMethod(obj:MyObj):List[String] = { 
    val xs = List[String]() 
    val xs1 = if (somecondition is satisfied) xs :+ " element" else xs 
    val xs2 = if (another condition) xs1 :+ " something else" else xs1 
    xs2 
} 

// #2. Better, but uses mutable builder. 
def someMethod(obj:MyObj):List[String] = { 
    val b = List.newBuilder[String] 
    if (somecondition is satisfied) b += " element" 
    if (another condition) b += " something else" 
    b.result 
} 

// #3. Best way IMO, but computationally expensive. 
def someMethod(obj:MyObj):List[String] = { 
    List[String]() ++ 
    Option("element").filter(some condition) ++ // for more correct semantics 
               // use LazyOption from Scalaz. 
    Option("something else").filter(another condition) 
} 
+0

如果過濾條件不是元素的函數,那麼'someBool option「元素」'是從Scalaz使用的漂亮皮條客。 –

+1

#3,我認爲這就是'++:'方法的設計目標:'Option(「element」)。filter(some condition)++:Option(「something else」)。filter(another condition)+ +:無'。這應該更有效率,因爲它預示着事情。 –

+0

@LuigiPlinge,是的,同意了。 – missingfaktor

4

而不是過濾單元,我寧願用一元或空列表:

def someMethod(obj:MyObj): List[String] = { 
    Nil ++ 
    (if (somecondition is satisfied) List(" element") else Nil) ++ 
    (if (another condition) .. List(" something else ") else Nil) ++ 
} 

編輯:關於下面的評論,如果你發現上面的代碼太冗長且難以維護,您仍然可以創建幫助功能:

def optElem[T](condition: Boolean)(value: => T): Option[T] = if (condition) Option(value) else None 
def someMethod(obj:MyObj): List[String] = { 
    Nil ++ 
    optElem (somecondition is satisfied)(" element") ++ 
    optElem (another condition)(" something else ") 
} 
+0

是的,更巧妙和高效 –

+0

順便說一句,這正是我發佈前的問題(我使用空列表)。我發現更加冗長......基本上,我正在尋找一種方法,在未來發生維護代碼的新開發人員會發現最困難的 – questionersam

1

另一個需要做的是構建一個選項列表,然後將列表弄平。

def f(obj: MyObj): List[String] = { 
    List(if (cond1(obj)) Some("element")  else None, 
     if (cond2(obj)) Some("something else") else None).flatten 
} 
相關問題