2013-03-29 19 views
7

Tôi có chức năng đệ quy mà tôi đang cố gắng thực hiện @tailrec bằng cách có phần bên trong, đệ quy (countR3) thêm các phần tử vào hàng đợi (agendascala.collections.mutable.Queue). Ý tưởng của tôi là sau đó có phần bên ngoài của hàm lặp trong chương trình làm việc và tổng hợp kết quả.Có cách nào thanh lịch để foldLeft trên scala.collections.mutable.Queue đang phát triển không?

LƯU Ý: vấn đề về bài tập về nhà, vì vậy tôi không muốn đăng toàn bộ mã; tuy nhiên, việc thực hiện đệ quy đuôi thực hiện là không phải là một phần của bài tập về nhà.

Dưới đây là phần mã liên quan đến câu hỏi của tôi:

import scala.collection.mutable.Queue 

val agenda: Queue[Tuple2[Int, List[Int]]] = Queue() 

@tailrec 
def countR3(y: Int, x: List[Int]): Int = { 
    if (y == 0) 1 
    else if (x.isEmpty) 0 
    else if … 
    else { 
    agenda.enqueue((y - x.head, x)) 
    countR3(y, x.tail) 
    } 
} 
⋮ 
agenda.enqueue((4, List(1, 2))) 
val count = agenda.foldLeft(0) { 
    (count, pair) => { 
    val mohr = countR3(pair._1, pair._2) 
    println("count=" + count + " countR3=" + mohr) 
    count + mohr 
    } 
} 
println(agenda.mkString(" + ")) 
count 

này gần dường như làm việc ... Vấn đề là nó không lặp qua tất cả các mục được bổ sung vào chương trình nghị sự, nhưng nó xử lý một số trong số đó. Bạn có thể thấy điều này trong đầu ra dưới đây: [. Trong số sáu mục trên chương trình nghị sự chính thức, chỉ có ba đầu tiên được xử lý]

count=0 countR3=0 
count=0 countR3=0 
count=0 countR3=0 
(4,List(1, 2)) + (3,List(1, 2)) + (2,List(2)) + (2,List(1, 2)) + (1,List(2)) + (0,List(2)) 

Tôi thường cũng nhận thức được sự nguy hiểm của đột biến một bộ sưu tập trong khi bạn đang lặp qua nó trong, ví dụ, Java. Nhưng một Hàng đợi là loại ngựa có màu khác. Tất nhiên, tôi hiểu rằng tôi chỉ đơn giản là có thể viết một vòng lặp bắt buộc, như vậy:

var count = 0 
while (!agenda.isEmpty) { 
    val pair = agenda.dequeue() 
    count += countR3(pair._1, pair._2) 
} 

này hoạt động hoàn hảo tốt, nhưng là Scala này, tôi khám phá để xem nếu có một hơn chức năng thanh lịch cách.

Mọi đề xuất?

Trả lời

2

Mặc dù có lẽ không hoàn toàn thành ngữ, bạn có thể thử này:

Stream.continually({ if (agenda.isEmpty) None else Some(agenda.dequeue()) }). 
    takeWhile(_.isDefined).flatten. 
    map({ case (x, y) => countR3(x, y) }). 
    toList.sum 
  • Các Stream.continually({ if (agenda.isEmpty) None else Some(agenda.dequeue()) }) mang đến cho bạn một dòng vô hạn các mặt hàng đợi bọc trong Option[Tuple2[Int, List[Int]]].
  • Sau đó, cắt giảm chuỗi ngay khi bắt đầu mục None đầu tiên, tức là khi hàng đợi cạn kiệt.
  • Vì cuộc gọi trước đó vẫn mang lại một chuỗi gồm Option, chúng tôi cần gỡ bỏ chúng bằng flatten.
  • map({ case (x, y) => countR3(x, y) }) về cơ bản áp dụng chức năng của bạn cho từng mục.
  • Và cuối cùng, toList buộc đánh giá luồng (đó là những gì chúng tôi đang làm việc) và sau đó sum tính tổng các mục của danh sách.

Tôi nghĩ rằng vấn đề với agenda.foldLeft (rằng nó xử lý chỉ 'một số' mặt hàng enqueued) là tôi đoán rằng phải mất một (có thể thay đổi) danh sách các mặt hàng hiện enqueued, và do đó không bị ảnh hưởng bởi các mục đã được thêm vào trong quá trình tính toán.

+0

Không chính xác thành ngữ, tôi đồng ý, nhưng có vẻ như nó sẽ phù hợp với hóa đơn hoạt động thuần túy hơn. Câu trả lời hay! Và thú vị là, 'chương trình nghị sự.foldLeft' đã được xử lý nhiều hơn chỉ là các mặt hàng enqueued ban đầu; nó không có vẻ đơn giản là làm việc trên một bản sao của hàng đợi ban đầu. Có lẽ nó đã dừng lại khi mục "cuối cùng" dẫn đến nhiều mục được thêm vào hàng đợi, hoặc một cái gì đó như thế. –

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