2010-11-25 5 views
7

私はボールローリングを開始します。頻繁に遭遇する問題のためにScalaに確立された共通のパターン/ソリューション

いくつかの要素が複数回含まれている場合、一般的な要件の1つは、タリーまたはヒストグラムの形でカウントすることです。

しばしば引用符で囲まれたソリューションは、次のとおりです。

ss.groupBy(identity).mapValues(_.size) 

だから、Scalaでは同様の一般的に遭遇する問題のために存在する他のどのような解決策?

答えて

3

Monoidsまたは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を持っている必要があります。しかし、ゼロの値が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 :-) 
+0

私はこの1つが好きです。(例えば、リスト( "a"、 "b"))( –

3

Scalaコレクションのデカルト積を生成する方法が何度も欠けていました。 Haskellでは、あなたは

import Control.Applicative 
(,) <$> [1,2,3] <*> ["a","b"] 

-- [(1,"a"),(1,"b"),(2,"a"),(2,"b"),(3,"a"),(3,"b")] 

for(x <- List(1,2,3); y <- List("a","b")) yield (x,y) 

があまりにも不器用であるScalaのソリューションを書くことができます。

+4

scalaz: '(リスト(1,2,3)| @ – Debilski

+1

)最も!それは私の主張することが許可されているので、私の質問です:) –

4

は私が...

我々は成功した出力を生成する、またはいくつかのエラーメッセージで失敗することがありプロセスの数を持っている問題の解決策を再び同じドラムを叩いたがいないということ。目標は、すべてのプロセスが成功し、1つ以上が失敗した場合、すべてのエラーメッセージを集約するために、成功した結果を集計することです。

これはscalaz検証することで解決することができます:まず、セットアップ一部の輸入

scala> import scalaz._; import Scalaz._ 
import scalaz._ 
import Scalaz._ 

は、今すぐ/失敗を集約するApplicativeを使用するのは、私たちの "プロセス"

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] 

を定義してみましょう成功:

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 
2

特定の条件condSome(x)を返す保持している場合は、他のリターンNone

Some(x) filter cond 

を[ポールフィリップスのポストメーリングリストの投稿から]

臆面もなくこの質問へのoxbow_lakes'答えから盗ま
3

Instantiating a case class from a list of parameters

引数を指定するタプルを使用する方法/関数を呼び出す:これは、任意の関数のために使用することができる

case class Foo(a: Int, b: String, c: Double) 
(Foo.apply _).tupled apply (1, "bar", 3.14) 

1

時にはあなたが代わりのための間、使用する必要があり、多くの場合、あなたは結果を収集している:

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) 
関連する問題