2010-12-27 34 views
22

Tôi có những gì tôi nghĩ là trường hợp phổ biến nhất để xử lý hàng đợi. Tôi sẽ đọc phần trước của hàng đợi, hành động trên phần tử (có thể khiến nhiều phần tử được thêm vào hàng đợi), và sau đó lặp lại cho đến khi hàng đợi rỗng.Tôi nên * sử dụng scala.collection.immutable.Queue như thế nào?

  1. bản năng đầu tiên của tôi là foreach, nhưng không có, rõ ràng là một hàng đợi (thậm chí có thể thay đổi một) là nghiêm ngặt và foreach vòng qua tất cả các yếu tố có trong hàng đợi khi lặp khởi động.
  2. Tôi không thể tìm ra cú pháp cho vòng lặp while.

Bạn sẽ nghĩ rằng nó sẽ là một cái gì đó giống như

while (!q.isEmpty) { 
    var (e, q) = q.dequeue 
    ... } 

sẽ làm việc, ngoại trừ việc tôi redeclaring q. Này không làm việc:

while (!q.isEmpty) { 
    var (e, q1) = q.dequeue 
    q = q1 
    ... } 

nhưng người đàn ông, nó trông sai ...

+2

Có vẻ sai nhưng không sao. –

Trả lời

17

Dưới đây là một cách để tránh bất kỳ vars tại tất cả:

val q0 = collection.immutable.Queue("1","Two","iii") 
Iterator.iterate(q0) { qi => 
    val (e,q) = qi.dequeue 
    println("I just dequeued "+e) // Your side-effecting operations go here 
    if (e.length!=2) q.enqueue("..") // Your changes to the queue go here 
    else q 
}.takeWhile(! _.isEmpty).foreach(identity) 

Bạn bắt đầu với hàng đợi ban đầu , q0, và sau đó trên bước thứ nhất qi, bạn dequeue một cái gì đó và tạo ra một hàng đợi mới nếu cần thiết, trả lại cho bước tiếp theo. Tất cả những gì bạn còn lại là điều kiện dừng (không trống), và sau đó vì điều này chỉ xác định một quy trình, chứ không phải là hành động thực tế, bạn phải chạy nó (ví dụ như sử dụng một for-no foreach).

+0

Bây giờ * đó là * tốt. Tôi đã không thử nó, nhưng đó là những gì tôi đã có trong tâm trí. Trên thực tế, việc bổ sung vào hàng đợi đang được thực hiện sâu trong cây cuộc gọi của các tác vụ phụ, vì vậy tôi có thể phải tạo một khu vực tạm thời có sẵn, nhưng tôi nghĩ nó sẽ hoạt động. – Malvolio

13

Trong khi Rex Kerr 's answer là tốt, trình lặp có thể thay đổi. Đây là một giải pháp thực sự không thay đổi, được mô phỏng rất chặt chẽ trên mã trong câu trả lời của Rex Kerr.

val q0 = collection.immutable.Queue("1","Two","iii") 
@annotation.tailrec def processQueue(queue: collection.immutable.Queue[String]): Unit = if (queue.nonEmpty) { 
    val (element, rest) = queue.dequeue 
    println("I just dequeued "+element) 
    if (element.length != 2) processQueue(rest.enqueue("..")) 
    else processQueue(rest) 
} 
processQueue(q0) 
+0

Mã đệ quy đuôi có thể thay đổi nội bộ; bạn chỉ được bảo vệ khỏi nó. Cho rằng mô hình trình vòng lặp, được sử dụng như tôi đã làm, cũng bảo vệ bạn khỏi các nội bộ có thể thay đổi được, tôi không thấy sự khác biệt trong trường hợp này. (Mặc dù tôi nghĩ rằng nó có giá trị để biết cách sử dụng đệ quy đuôi nữa; nó chỉ thường có cú pháp khó xử hơn cho những loại vấn đề này.) –

+1

@Rex Kerr Mỗi mã có thể thay đổi nội bộ, bởi vì tất cả các bộ vi xử lý thực sự chúng ta sử dụng không thể làm một điều duy nhất mà không có khả năng biến đổi, vì vậy lập luận đó hoàn toàn là bollocks. Đó là một tối ưu hóa trình biên dịch không liên quan đến lập trình viên. –

+6

Nếu tôi không nhận được gì khác từ câu hỏi này và các câu trả lời khác nhau, đó là cụm từ "lập luận đó là tuyệt đối bollocks", mà tôi dự định sẽ sử dụng ở cơ hội rất tiếp theo và thường xuyên sau đó. – Malvolio

4

xử lý một Queue trong một vòng lặp while thể được thực hiện mà không có một bản sao var/val như sau:

var q = Queue("foo", "bar", "baz") 
while (q.nonEmpty) { 
    val e = q.head 
    q = q.tail 
    // Do something with `e` here 
} 

(Tôi biết rằng câu trả lời này là 7 năm muộn, nhưng tôi nghĩ rằng đó là một lựa chọn có giá trị dù sao.)

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