ボールを転がし始めます。
いくつかの要素が複数回含まれる可能性がある一連の要素が与えられた場合、典型的な要件の 1 つは、集計またはヒストグラムの形式でそれらをカウントすることです。
よく引用される解決策は次のとおりです。
ss.groupBy(identity).mapValues(_.size)
では、Scala でよく遭遇する同様の問題に対して、他にどのような解決策があるのでしょうか?
ボールを転がし始めます。
いくつかの要素が複数回含まれる可能性がある一連の要素が与えられた場合、典型的な要件の 1 つは、集計またはヒストグラムの形式でそれらをカウントすることです。
よく引用される解決策は次のとおりです。
ss.groupBy(identity).mapValues(_.size)
では、Scala でよく遭遇する同様の問題に対して、他にどのような解決策があるのでしょうか?
また同じ太鼓叩いてるわけじゃないけど…
成功した出力を生成するか、何らかのエラーメッセージで失敗する可能性のあるプロセスが多数あるという問題の解決策。目標は、すべてのプロセスが成功した場合は成功した結果を集計し、1 つ以上のプロセスが失敗した場合はすべてのエラー メッセージを集計することです。
これはscalazバリデーションで解決できます:まず、いくつかのインポートをセットアップします
scala> import scalaz._; import Scalaz._
import scalaz._
import Scalaz._
次に、「プロセス」を定義しましょう
scala> def fooI(s : String) : ValidationNEL[Exception, Int] = s.parseInt.liftFailNel
fooI: (s: String)scalaz.Scalaz.ValidationNEL[Exception,Int]
scala> def fooF(s : String) : ValidationNEL[Exception, Float] = s.parseFloat.liftFailNel
fooF: (s: String)scalaz.Scalaz.ValidationNEL[Exception,Float]
scala> def fooB(s : String) : ValidationNEL[Exception, Boolean] = s.parseBoolean.liftFailNel
fooB: (s: String)scalaz.Scalaz.ValidationNEL[Exception,Boolean]
Applicative
失敗/成功を集計するために使用します。
scala> def attempt(ss : String*) = (fooI(ss(0)) <|**|> (fooF(ss(1)), fooB(ss(2)))) match {
| case Success((i, f, b)) => println("Found " + i + " " + f + " " + b)
| case Failure(es) => es foreach println
| }
attempt: (ss: String*)Unit
それでは、いくつかの失敗を試してみましょう。
scala> attempt("a", "b", "true")
java.lang.NumberFormatException: For input string: "a"
java.lang.NumberFormatException: For input string: "b"
それでは、成功を目指しましょう。
scala> attempt("1", "2.3", "false")
Found 1 2.3 false
Monoid
s またはs を使用Numeric
して、必要に応じて暗黙を使用して、豊富なクラスの適切な操作を定義します。
case class Money(ccy: Currency, amount : BigDecimal) {
def +(that : Money) = {
require(this.currency == that.curency)
copy(amount = this.amount + that.amount)
}
def abs = copy(amount = amount.abs)
}
それでは、 のコレクションがあり、Money
それらを合計したいとしましょう。
val turnover = trades.map(_.usdValue.abs).∑ //no implicit monoid :-(
しかし、これを行うには、暗黙的なMonoid
. しかしもちろん、a のゼロ値は、Money
すでに通貨を持っている場合にのみ意味があります!
implicit def CurrencyMonoid(implicit currency : Currency) = new Monoid[Currency] {
def zero = Money(currency, 0)
def append(m1 : Money, m2 : Money) = m1 + m2
}
したがって、Scala はこれらの暗黙の両方を使用します。
implicit val usd = Currency.USD
val turnover = trades.map(_.usdValue.abs).∑ //yay for monoids :-)
この質問に対する oxbow_lakes の回答から恥知らずに盗まれた:パラメーターのリストからケース クラスをインスタンス化する
タプルを使用して引数を提供するメソッド/関数を呼び出す:
case class Foo(a: Int, b: String, c: Double)
(Foo.apply _).tupled apply (1, "bar", 3.14)
これは、任意の機能に使用できます。
Scala コレクションのデカルト積を生成する方法を何度か見逃しました。Haskell では次のように記述できます。
import Control.Applicative
(,) <$> [1,2,3] <*> ["a","b"]
-- [(1,"a"),(1,"b"),(2,"a"),(2,"b"),(3,"a"),(3,"b")]
Scala ソリューション
for(x <- List(1,2,3); y <- List("a","b")) yield (x,y)
不器用すぎる。
特定の条件cond
が成り立つ場合は return Some(x)
、そうでない場合は return None
:
Some(x) filter cond
[メーリングリストの Paul Phillips の投稿からピックアップ]
for の代わりに while を使用する必要がある場合もあり、多くの場合、結果を収集しています。
val buf = new Listbuffer[Int]
while(cond()) {
val x = fancyStuff()
buf += calculation(x)
}
while
の場合と同じように何かを「生成」する可能性がfor
あり、命令型と関数型のスタイルの間の端にあるぎざぎざを取り除くと非常に役立つと思います。
val buf = while(cond()) {
val x = fancyStuff()
} yield calculation(x)