2011-10-10 35 views
7

Tôi đã tự hỏi làm thế nào bạn sẽ viết một phương thức trong Scala có hàm f và một danh sách đối số args trong đó mỗi arg là một phạm vi. Giả sử tôi có ba đối số (Range(0,2), Range(0,10)Range(1, 5)). Sau đó, tôi muốn lặp lại trên f với tất cả các khả năng của ba đối số đó.xác minh phân phối xác suất với các đối số biến tổng cộng 1

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

Tuy nhiên, tôi muốn phương pháp này hoạt động cho các hàm có số lượng đối số thay đổi. Điều này có thể không?

Chỉnh sửa: có cách nào để thực hiện điều này khi chức năng không lấy danh sách, nhưng thay vào đó có danh sách tham số chuẩn hoặc được thu thập?

+1

Tôi nghĩ rằng có thể thông qua đệ quy, nhưng chỉ nếu 'f' chấp nhận danh sách các giá trị. –

+0

Tôi đã hy vọng để giải quyết nó mà không có hạn chế này ('f' mất một danh sách tham số tiêu chuẩn hoặc là curried). – schmmd

Trả lời

6

Đó là một câu hỏi thực sự tốt!

Bạn muốn chạy flatMap theo thứ tự trên danh sách các yếu tố có kích thước tùy ý. Khi bạn không biết danh sách của bạn dài bao lâu, bạn có thể xử lý nó với đệ quy hoặc tương đương với một lần.

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)) 

(Nếu bạn không thể tìm ra mã, đừng lo lắng, học cách sử dụng Hooglesteal it from Haskell)

Bạn có thể làm điều này với Scalaz (nói chung nó bắt đầu với một F[G[X]] và trả về một G[F[X]], cho rằng các nhà thầu loại GF có khả năng TraverseApplicative tương ứng.

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

Câu trả lời hay - Tôi chắc chắn sẽ phải kiểm tra scalaz. – schmmd

1

Đó nhiều hơn hoặc ít hơn sẽ thực hiện công việc (mà không áp dụng f, mà bạn có thể thực hiện riêng rẽ)

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

Bạn có thể sau đó chỉ cần lập bản đồ chức năng của bạn về điều đó. Tôi không chắc chắn đó là một thực hiện rất hiệu quả mặc dù.

0

Đó là câu trả lời từ góc nhìn đệ quy. Thật không may, không quá ngắn như những người khác.

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

Hãy xem this answer. Tôi sử dụng mã này cho chính xác mục đích này. Nó được tối ưu hóa một chút. Tôi nghĩ rằng tôi có thể sản xuất một phiên bản nhanh hơn nếu bạn cần.

Các vấn đề liên quan