2

Im a beginner at a scala and am looking for the best/idiomatic way to do what I intend to do here.

This is what I want to do

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


}

つまり、このメソッドは入力パラメーター オブジェクトのいくつかのプロパティをチェックし、要素を List に追加します (つまり、返されます)。どの条件も満たされない場合は、空のリストを返す必要があります。

  1. もちろん、コードはコンパイルされません。しかし、どういうわけか、 List[T] + Unit が List[T] を返す必要があることは直感的に思えます。なぜ私は間違っているのですか?

そして 2. この Scala の正しいやり方を教えてください。条件のリストを反復処理する場合は、内包表記を使用できたはずです。

4

4 に答える 4

4

Unit をフィルタリングするのではなく、単項または空のリストを使用します。

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 " )
}
于 2012-09-13T08:43:52.383 に答える
3

if-elseは Scala の式です。あなたが書いたものは次のようになります:

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

ご覧のとおり、一般的なブランチ タイプはUnitです。

式全体の型は、 andList[Any]の共通のスーパータイプであるため、 にStringなりUnitます。

あなたが望むものを達成するためのいくつかの方法:

// #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)
} 
于 2012-09-13T08:39:24.620 に答える
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)最初に、タイプでフィルタリングされます。ユニットはcollect内の型条件を満たさないため、結果は空になります文字列のリスト

良い点は、filterメソッドcollectが可能な限り厳密な型を選択するのとは異なり(したがって、文字列のシーケンスを取得します。これは、collect内の関数から推測されます)。

もう1つの可能性は、に置き換えることです.collect { ... }flatten、タイプ情報は失われます。

于 2012-09-13T08:27:15.253 に答える
1

これに対する別の見方は、オプションのリストを作成してから、リストをフラット化することです。

def f(obj: MyObj): List[String] = {
  List(if (cond1(obj)) Some("element")        else None,
       if (cond2(obj)) Some("something else") else None).flatten
}
于 2012-09-13T12:12:11.537 に答える