使用迭代器在Groovy中进行“Peeking”操作?

7
我在循环中有各种情况需要“窥视”或“跳过”,以便迭代处理项。其中一个场景是我正在枚举文件的行,而在行末尾有一个“连续”字符,表示将下一行与当前行组合。如果我只是简单地循环,那就不太难,我只需读取下一行并增加我的计数器/索引即可。
但是使用迭代器时,这种模式并不明显。实际上,我想要在不退出闭包的情况下消耗下一行或多行。但我甚至不确定是否可能做到这一点。是否有任何良好的设计模式可以使用闭包来实现此迭代模式,以便我不必使用不太灵活的循环?也许这是一种迭代器形式,具有一些用于推入/弹出处理项的堆栈?

3
我通常会在迭代器周围使用一个装饰器,就像这样:https://gist.github.com/ataylor284/5389604 - ataylor
3个回答

1

我曾经需要实现类似的功能。我有一个包含每行以管道分隔的数据的大文件,数据可以继续到下一行,但只有在“窥视”下一行后才能知道。最终我使用了ArrayList作为堆栈,并结合peek方法:

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

1
我会制作一个迭代器,负责合并行。对于换行示例,迭代器可以在其构造函数中读取从文件中读取的行,然后通过其next方法从这些行中读取内容,在发现延续字符时提前读取,以便在管道的下一步之前解析延续字符。因此,所需的任何状态机都将包含在迭代器内部。

0

有趣的问题。

这里的关键问题是需要在迭代中保留一些状态。

一种解决方法是使用外部变量(这里我使用字符串数组和 List#each 而不是文件和 File#eachLine,但它们应该是类似的):

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 = ''
  }
}

另一种方法是使用一个专门设计用于在迭代中传递状态的迭代器,例如{{link1: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) }

在这种情况下,我们首先将连续的行连接起来,然后再处理它们。
在两种情况下输出结果都是:
Processing "Single line."
Processing "Long line continuation."
Processing "Single line."

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接