F#:想要重新初始化枚举器

时间:2012-01-16 13:42:11

标签: f# ienumerable

我有一系列素数除数,我想为每个主要候选者迭代。我使用GetEnumerator()MoveNext()和Current。我无法重新初始化枚举器,从头开始。我尝试了编译的Reset(),但是给出了一个未实现的运行时错误。

我正在使用F#2.0 Interactive build 4.0.40219.1

有什么建议吗?

此致 道格


澄清问题:对于每个主要候选者N,我想通过素数除数序列(最多约为平方N)进行迭代并完全考虑因子N或确定它是否为素数。使用GetEnumerator,MoveNext,Current方法适用于第一个主要候选者,但是在第二个主要候选者上我想从头开始迭代我的除数序列。似乎这样做的唯一方法是创建一个新的迭代器(对于大量的主要候选者来说很难)或创建一个新的素数序列(我不想这样做)。

使用诸如“seqPrimes中的除数”这样的东西的建议似乎会在停止之前耗尽所有除数,但是我想在主要除数除以主要候选者时立即停止。

如果上述陈述中的逻辑错误,请告诉我。

我调查了Seq.cache,这对我有用。结果代码如下:


// Recursive isprime function (modified from MSDN)
let isPrime n =
    let rec check i =
        i > n/2 || (n % i <> 0 && check (i + 2))
    if n = 2 then true
    elif (n%2) = 0 then false
    else check 3

let seqPrimes = seq { for n in 2 .. 100000 do if isPrime n then yield n }

// Cache the sequence to avoid recomputing the sequence elements.
let cachedSeq = Seq.cache seqPrimes


// find the divisors of n (or determine prime) using the seqEnum enumerator 
let rec testPrime n (seqEnum:System.Collections.Generic.IEnumerator<int>) =
  if n = 1 then printfn "completely factored"
  else
    let nref = ref n
    if seqEnum.MoveNext() then
      let divisor = seqEnum.Current
      //printfn "trial divisor %A" divisor
      if divisor*divisor > n then printfn "prime %A" !nref
      else
        while ((!nref % divisor) = 0) do
          printfn "divisor %A" divisor
          nref := !nref / divisor
        testPrime !nref seqEnum

// test
for x = 1000000 to 1000010 do
  printfn "\ndivisors of %d = " x
  let seqEnum = cachedSeq.GetEnumerator()
  testPrime x seqEnum
  seqEnum.Dispose()   // not needed

1 个答案:

答案 0 :(得分:3)

如果您的意思是尝试重置枚举器的原因是重新生成素数序列的成本很高,您可以考虑caching您的序列。这种使用你的序列的方式对于F#来说是惯用的。为了向您展示如何执行此操作,我将引用您从this context获取的以下代码段:

let rec primes = 
    Seq.cache <| seq { yield 2; yield! Seq.unfold nextPrime 3 }
and nextPrime n =
    if isPrime n then Some(n, n + 2) else nextPrime(n + 2)
and isPrime n =
    if n >= 2 then
        primes 
        |> Seq.tryFind (fun x -> n % x = 0 || x * x > n)
        |> fun x -> x.Value * x.Value > n
    else false

您可以使用此代码段来查看此处重新枚举的惩罚可以忽略不计。

谈到Reset()的{​​{1}}方法,我记得它在当前的F#中没有实现,即抛出IEnumerator。请参阅MSDN reference了解理由。

<强>此外: 为了使用您在下面建议的测试进行测试:

System.NotSupportedException

在我的笔记本电脑上,测试执行仅需3毫秒。