2011-10-10 8 views
7

関数fと引数のリストargs(それぞれの引数は範囲です)をとる方法をScalaで書く方法は不思議でした。 3つの引数(Range(0,2),Range(0,10)、およびRange(1, 5))があるとします。そして、私はf以上の3つの引数のすべての可能性を反復したいと思います。可変引数を持つ確率分布を検証する合計1

var sum = 0.0 
for (a <- arg(0)) { 
    for (b <- arg(1)) { 
    for (c <- arg(2)) { 
     sum += f(a, b, c) 
    } 
    } 
} 

しかし、このメソッドは、可変数の引数を持つ関数に対して機能します。これは可能ですか?

編集:関数がリストを取るのではなく、標準のパラメータリストを取るか、カイトしたときにこれを行う方法はありますか? (あなたが個別に行うことができますfは、適用しない)多かれ少なかれ仕事をするだろう

+1

再帰によっても可能ですが、 'f'が値のリストを受け入れる場合のみです。 –

+0

私はこの制限なしで(fは標準のパラメータリストを取るか、またはカレー化しています)、この問題を解決することを望んでいました。 – schmmd

答えて

6

これは本当に良い質問です!

flatMapを任意のサイズの要素のリストの上に順番に実行します。あなたのリストがどれくらいの長さであるか分からないときは、再帰で処理することも、等価的に折り畳みで処理することもできます。

scala> def sequence[A](lss: List[List[A]]) = lss.foldRight(List(List[A]())) { 
    | (m, n) => for (x <- m; xs <- n) yield x :: xs 
    | } 
scala> sequence(List(List(1, 2), List(4, 5), List(7))) 
res2: List[List[Int]] = List(List(1, 4, 7), List(1, 5, 7), List(2, 4, 7), List(2 
, 5, 7)) 

(あなたは、コードを理解することはできません場合は、Hooglesteal it from Haskellを使用する方法を学び、心配しないでください)

あなたはScalazでこれを行うことができます(一般的には、それはF[G[X]]で始まり、型コンストラクタGFそれぞれTraverseApplicative能力を有することを考えると、G[F[X]]を返す。

scala> import scalaz._ 
import scalaz._ 

scala> import Scalaz._ 
import Scalaz._ 

scala> List(List(1, 2), List(4, 5), List(7)).sequence 
res3: List[List[Int]] = List(List(1, 4, 7), List(1, 5, 7), List(2, 4, 7), List(2 
, 5, 7)) 

scala> Seq(some(1), some(2)).sequence 
res4: Option[Seq[Int]] = Some(List(1, 2)) 

scala> Seq(some(1), none[Int]).sequence 
res5: Option[Seq[Int]] = None 
+0

クールな答え - 私は確かにscalazをチェックアウトする必要があります。 – schmmd

1

def crossProduct[A](xxs: Seq[A]*) : Seq[Seq[A]] 
    = xxs.foldLeft(Vector(Vector[A]())){(res, xs) => 
     for(r <- res; x <- xs) yield r :+ x 
    } 

それからちょうどその上で、あなたの機能をマッピングすることができます。私はそれが非常に効率的な実装だと確信していません。

0

それは再帰的な観点からの答えです。残念ながら、他の人ほど短くはありません。

def foo(f: List[Int] => Int, args: Range*) = { 
    var sum = 0.0 
    def rec(ranges: List[Range], ints: List[Int]): Unit = { 
     if (ranges.length > 0) 
     for (i <- ranges.head) 
      rec(ranges.tail, i :: ints) 
     else 
     sum += f(ints) 
    } 
    rec(args.toList, List[Int]()) 
    sum 
    } 
0

this answerをご覧ください。私はこの目的のためにこのコードを使用します。わずかに最適化されています。私はあなたが必要な場合は、私はより高速なバージョンを生成することができると思う。

関連する問題