【问题标题】:how to iterate with two iterators如何使用两个迭代器进行迭代
【发布时间】:2020-09-26 12:38:58
【问题描述】:

我想使用nimbioseq 并迭代两个具有相同序列数的文件(使用readSeq()iterator),如:

for seq1, seq2 in readSeq(file1), readSeq(file2):
  echo seq1.id, "\t", seq2.id

对于这种情况,我想我需要某种“压缩”运算符,我无法理解如何使用 [ 发现:https://hookrace.net/nim-iterutils/iterutils.html#zip.i ,,Iterable[S] ].

或者了解如何在 for 循环之外获得单个“迭代”(如果可能):

for seq1 in readSeq(file1):
  let seq2 = readSeq(file2);
  echo seq1.id, "\t", seq2.id

感谢您的帮助!

【问题讨论】:

  • 我真的要感谢大家的精彩回答。我做了一些测试,但需要完成,并会尽快提供反馈。

标签: loops iterator nim-lang


【解决方案1】:

来自 iterutils 的toClosure 是有限的,但你可以:

import iterutils

template initClosure(id,iter:untyped) =
  let id = iterator():auto{.closure.} =
    for x in iter:
      yield x

initClosure(f1,readSeq(file1))
#creates a new closure iterator, 'f1'

initClosure(f2,readSeq(file2))
#creates a new closure iterator, 'f2'

for seq1,seq2 in zip(f1,f2):
  echo seq1.id,"\t",seq2.id

编辑:感谢@pietropeter 指出错误,这是他们使用此模板重写的示例:

import iterutils
template initClosure(id:untyped,iter:untyped) =
  let id = iterator():auto {.closure.} =
    for x in iter:
      yield x

iterator letters: auto =
  for c in 'a' .. 'z':
    yield c

# Now requires a parameter
iterator numbers(s: int): int =
  var n = s
  while true:
    yield n
    inc n

initClosure(cletter,letters())
initClosure(numbers8,numbers(8))

for (c, n) in zip(cletter, numbers8):
  echo c, n

【讨论】:

  • 我喜欢模板方法,我试图将它应用到扩展版本,但失败了:play.nim-lang.org/#ix=2z4b我做错了什么?
  • 感谢您指出这一点,我的 id 和 iter 仍然从我的宏解决方案中引用,所以我很糟糕。对代码的唯一更改是在字母后添加括号。
  • 完美!现在对我来说这是最好的答案
【解决方案2】:

我将使用this iterators code from Manual,并将您的问题插入其中。我确信它还有改进的空间:

type
  Task = iterator (r: var int)

iterator f1(r: var int){.closure.} =
  for n in [1, 3, 5]:
    r = n
    yield

iterator f2(r: var int){.closure.} =
  for n in [2, 4, 6]:
    r = n
    yield

proc runTasks(t: varargs[Task]) =
  var ticker = 0
  var r: int

  while true:
    var x = t[ticker mod t.len]
    x(r)
    echo r
    if finished(x): break
    inc ticker

runTasks(f1, f2)

您将在输出中看到 1,2,3,4,5,6,6(finished 容易出错,如手册中所述,并返回最后一项两次)。您必须更新代码,将r: var int 替换为返回readSeq(file) 的任何类型(我认为是r: var Record),并将迭代器for n in [1, 2, 3] 替换为for s in readSeq(file)

【讨论】:

    【解决方案3】:

    如果您想要的行为类型是zip,那么来自 iterutils 的行为似乎可以正常工作。唯一需要注意的是它需要闭包迭代器(请参阅manual 了解内联迭代器和闭包迭代器之间的区别)。示例(https://play.nim-lang.org/#ix=2yXV):

    import iterutils
    
    iterator letters: char {.closure.} =
      for c in 'a' .. 'z':
        yield c
    
    iterator numbers: int {.closure.}=
      var n = 1
      while true:
        yield n
        inc n
    
    for (c, n) in zip(letters, numbers):
      echo c, n
    

    我看到 nimbioseq 中的 readseq 不是关闭,但可能这样的东西可以工作(编辑:它不应该,见下文):

    iterator closureReadSeqs(filename: string): Record {.closure.} =
      for rec in readSeqs(filename):
        yield rec
    

    编辑

    对于在 cmets 中带有参数的迭代器,解决方法是让 proc 返回一个迭代器(在这种情况下,默认情况下它将是一个闭包迭代器)。更新示例 (https://play.nim-lang.org/#ix=2z0e):

    import iterutils
    
    iterator letters: char {.closure.} =
      for c in 'a' .. 'z':
        yield c
    
    # Now requires a parameter
    proc numbers(s: int): iterator(): int =
      return iterator(): int =
        var n = s
        while true:
          yield n
          inc n
    
    let numbers8 = numbers(8)
    for (c, n) in zip(letters, numbers8):
      echo c, n
    

    现在我对如何为nimbioseq 进行这项工作的最佳猜测是:

    proc closureReadSeqs(filename: string): iterator(): Record =
      return iterator(): Record =
        for rec in readSeqs(filename):
          yield rec
    

    【讨论】:

    • 非常感谢您的帮助。我目前没有得到的是如何将zip 与需要参数的闭包一起使用。我尝试使用您的closureReadSeqs,但可能我的错误在于我如何使用zip。我尝试扩展您的示例:gist.github.com/telatin/3e37d356937b1b2155b50b546ebb8982
    • 你是对的,所提出的方法不适用于需要参数的迭代器。迭代器语义有点棘手(参见另一个例子:stackoverflow.com/questions/63884552/…)。我更新了我的答案,扩展示例现在可以工作了(我使用了这里提到的方法:nim-by-example.github.io/for_iterators)。如果这对 nimbioseq 也有帮助,请告诉我。
    • 另外,由于 nim 中的迭代器和 proc 具有不同的命名空间(这是一个有点弃用的功能,但可能会保留一段时间:github.com/nim-lang/Nim/issues/8901),您应该能够将上述 proc 命名为 readSeqs 和它应该可以正常工作。
    • 嗨@Andrea T。我批准了对 python 语法高亮的编辑,因为它是目前使用 Nim 进行语法高亮的最佳选择。我仍然希望我们很快就会有本机语法突出显示。他们最近将高亮引擎从 prettify 更改为 highlight.js,它确实支持 Nim。据我了解,他们在迁移的第一阶段仍然保持相同范围的美化语言,但我希望 Nim 将很快得到支持。 meta.stackexchange.com/questions/184108/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    相关资源
    最近更新 更多