【问题标题】:F# seq.skipWhile not having expected behavior (skipping the whole sequence)F# seq.skipWhile 没有预期的行为(跳过整个序列)
【发布时间】:2016-03-04 06:17:08
【问题描述】:

我正在编写一个程序,它比较远程文件的内容并实时记录(而不是下载文件并每次用它的最新“版本”替换它)它的内容到本地文件。为此,我创建了一个 FTP 连接,读取远程文件,跳过所有内容直到读取的最后一行,然后将所有新行复制到本地文件中。

为了比较新与否,我使用了以下函数:

let getNewLines (lineToLookFor:string) (varLogLines:seq<string>) =
    let newLines = Seq.skipWhile ((fun (lineToMatch:string) (varLogLine:string) -> not(lineToMatch.Equals(varLogLine))) lineToLookFor) varLogLines
    match Seq.length newLines with
    | 0 -> (varLogLines, lineToLookFor)  // There has been a rollover of the messages file, take all the lines as they are all new
    | _ -> (newLines, Seq.last newLines) // Only take the new lines which were written since the last check in the messages file

Seq.skipWhile 应该跳过 seq 中谓词函数返回 true 的所有条目,然后返回 seq 的其余部分。就我而言,我想读取所有行,直到 lineToMatch.Equals(varLogLine),然后在 seq 中返回该点之后的所有其他内容。

不幸的是,newLines 总是空的,因此我的程序的流程总是在第一个匹配中进行 | 0->。我不知道为什么。

为了记录,我也尝试过 Contains 而不是 Equals,但没有任何成功。

【问题讨论】:

  • 您的代码看起来不错(例如,getNewLines "x" [for c in 'a' .. 'z' -&gt; string c] 的结果符合预期)。也许您的lineToLookFor 以回车或其他内容结尾?

标签: .net parsing f#


【解决方案1】:

您可以使用以下代码简化Seq.skipWhile 中的函数:

let getNewLines (lineToLookFor:string) (varLogLines:seq<string>) =
    let newLines = Seq.skipWhile (fun varLogLine -> varLogLine <> linetoLookFor) varLogLines
    match Seq.length newLines with
    | 0 -> (varLogLines, lineToLookFor)  // There has been a rollover of the messages file, take all the lines as they are all new
    | _ -> (newLines, Seq.last newLines) // Only take the new lines which were written since the last check in the messages file

或者,如果您想要的只是“我要查找的行之后的所有行”,您可以这样做:

let getNewLines (lineToLookFor:string) (varLogLines:seq<string>) =
    let maybeIndex = Seq.tryFindIndex (fun line -> line = lineToLookFor) varLogLines
    match maybeIndex with
    | Some index -> Seq.skip (index + 1) varLogLines // return the elements after the one you provided
    | None -> varLogLines // return all elements.

然后您可以获取该函数的结果并存储最后一个条目以供以后使用 - 您以前在 getNewLines 中执行此操作,但我觉得让调用者处理该工作更清洁:

let newLines = getNewLines lastLine varLogLines
let newLastLine = Seq.last newLines

编辑:看起来你在没有匹配的时候返回原来的lineToLookFor——感觉你应该返回Seq.last lineToLookFor

另外,如果您使用 CCR 并且可以避免让这个特定功能使用它,我肯定会避免使用它。该功能很简单,我认为您不需要将其包装在 ccr { } 块中,而且我之前被 CCR 咬过,因为它们看起来应该可以正常工作,但最终却没有这样做。

【讨论】:

  • 很遗憾,我在使用您的替代代码时遇到了同样的问题。
  • @Choub890 你是否相信这是一个seq&lt;string&gt; 而不是另一个非惰性类型?从列表构建 seq 时我没有看到任何问题,但如果 Seq 实际上是一个 IEnumerable 并且您不能多次枚举,事情可能会有所不同。
  • varLogLines 是一个使用 seq.ofArray 由字符串数组创建的 seq。我是否遗漏了与数组、列表和其他内容创建的序列相关的内容?
  • @Choub890 不,应该没问题。无论如何,字符串数组也是 seq ,因此您可以将其按原样传递给函数。您是否在调试器中查看了函数的参数,看看您传入的数据是否真的是您期望的数据?
  • 是的,我已经检查了前 20-30 个左右的项目,它们似乎正是我所期望的。我开始怀疑的唯一另一件事是我们对 ccr 的使用以及我的代码是以异步方式完成的。调用者函数实际上是与 ccr 异步生成的,我开始认为这对 getNewLines 有影响?
猜你喜欢
  • 2015-11-04
  • 2018-09-12
  • 2023-01-18
  • 2012-05-15
  • 2021-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多