2013-04-15 32 views
7

Tôi có các tình huống khác nhau trong các vòng mà tôi sẽ 'peek' hoặc 'bỏ qua' phía trước trong khi lặp qua các mục để xử lý.Groovy 'Peeking' phía trước với một trình lặp?

Một kịch bản là tôi liệt kê thông qua các dòng của một tệp và có ký tự 'tiếp tục' ở cuối dòng cho biết để kết hợp dòng tiếp theo với dòng hiện tại. Nếu tôi chỉ đơn giản là looping mà không phải là quá khó, tôi chỉ có thể đọc dòng tiếp theo, và bump counter/index của tôi.

Nó không phải là rõ ràng là mô hình để làm điều này với iterator của tôi. Tôi thực sự muốn tiêu thụ (các) dòng tiếp theo mà không thoát khỏi sự đóng cửa của tôi. Nhưng tôi thậm chí không chắc chắn nếu điều đó là có thể. Có bất kỳ mẫu thiết kế tốt nào cho mẫu lặp này bằng cách sử dụng một kết thúc, vì vậy tôi không phải dùng đến một vòng lặp ít hấp dẫn hơn? Nó có lẽ là một hình thức của iterator với một số ngăn xếp cho đẩy/popping mục để xử lý?

+3

Tôi thường sử dụng một trang trí xung quanh iterator như thế này: https://gist.github.com/ataylor284/5389604 – ataylor

Trả lời

1

Tôi muốn tạo một trình vòng lặp có thể chịu trách nhiệm kết hợp các dòng. Đối với ví dụ tiếp tục dòng, trình lặp có thể lấy các dòng được đọc từ tệp trong hàm khởi tạo của nó, sau đó có phương thức next đọc từ các dòng, đọc trước khi tìm thấy ký tự tiếp tục, để các ký tự tiếp tục được giải quyết trước bước trong đường ống. Vì vậy, bất kỳ máy nhà nước bạn cần sẽ được chứa trong vòng lặp.

1

Tôi đã phải triển khai điều gì đó tương tự đôi khi trước đây. Tôi đã có một tệp lớn với dữ liệu được phân tách bằng đường ống trên mỗi dòng và dữ liệu có thể tiếp tục trong dòng tiếp theo, nhưng tôi chỉ có thể biết nếu tôi "lén" dòng tiếp theo. Tôi đã kết thúc bằng cách sử dụng ArrayList dưới dạng ngăn xếp kết hợp với phương pháp nhìn trộm:

def list = [1, 2, 3, 4, 5, 6, 7] 

list.metaClass.peek = { delegate[-1] } 

assert list.pop() == 7 
assert list.pop() == 6 
assert list.peek() == 5 
assert list.peek() == 5 
assert list.pop() == 5 
assert list.pop() == 4 
assert list.peek() == 3 
0

Câu hỏi thú vị.

Vấn đề chính ở đây là bạn cần phải thực hiện một số trạng thái thông qua các lần lặp.

Một cách để làm điều này có thể được sử dụng một biến bên ngoài (ở đây tôi đang sử dụng một mảng các chuỗi và List#each thay vì một tập tin và File#eachLine, nhưng họ nên được tương tự):

def lines = [ 
    "Single line.", 
    "Long \\", 
    "line \\", 
    "continuation.", 
    "Single line." 
] 

def processLine(line) { println "Processing \"$line\""} 

def continuation = '' 
lines.each { line -> 
    line = continuation + line 
    if (line.endsWith('\\')) { 
    continuation = line.take(line.size() - 1) 
    } 
    else { 
    processLine(line) 
    continuation = '' 
    } 
} 

Một cách thứ nhất là sử dụng một iterator thiết kế đặc biệt để thực hiện nhà nước mặc dù interations, như Collection#inject:

lines = lines.inject([]) { list, line -> 
    if (list && list[-1].endsWith('\\')) 
    list[-1] = list[-1][0..-2] + line 
    else 
    list << line 
    list 
} 

lines.each { processLine(it) } 

Trong trường hợp này chúng ta lần đầu tiên gia nhập dòng tiếp tục và sau đó xử lý chúng.

Trong cả hai trường hợp đầu ra là:

Processing "Single line." 
Processing "Long line continuation." 
Processing "Single line."