测试有序的无限流是否包含值

时间:2011-09-28 19:35:01

标签: scala stream primes

我有一个无限的素数流primeStream(从2开始增加)。我还有另一个Ints s流,其数量增加,我想测试这些是否都是素数。

有效的方法是什么?我可以定义

def isPrime(n: Int) = n == primeStream.dropWhile(_ < n).head

但这似乎效率低下,因为它每次都需要迭代整个流。

primeStream的实施(从其他地方无耻地复制):

  val primeStream: Stream[Int] =
  2 #:: primeStream.map{ i =>
    Stream.from(i + 1)
    .find{ j =>
      primeStream.takeWhile{ k => k * k <= j }
        .forall{ j % _ > 0 }
    }.get
  }

3 个答案:

答案 0 :(得分:5)

如果问题是关于实现isPrime,那么你应该按照rossum的建议去做,即使划分成本超过相等测试,并且对于较低的n值,质数更密集,它会渐近地快得多。此外,在测试具有小除数(大多数数字)

的非素数时,它非常快

如果您想测试另一个不断增加的Stream的元素的素数,则可能会有所不同。您可以考虑类似于合并排序的东西。你没有说明你想要如何得到你的结果,这里是一个布尔流,但它不应该太难以适应其他东西。

/** 
 *  Returns a stream of boolean, whether element at the corresponding position
 *  in xs belongs in ys. xs and ys must both be increasing streams.
 */
def belong[A: Ordering](xs: Stream[A], ys: Stream[A]): Stream[Boolean] = {
   if (xs.isEmpty) Stream.empty
   else if (ys.isEmpty) xs.map(_ => true)
   else Ordering[A].compare(xs.head, ys.head) match {
     case less if less < 0 => false #:: belong(xs.tail, ys)
     case equal if equal == 0 => true #:: belong(xs.tail, ys.tail)
     case greater if greater > 0 => belong(xs, ys.tail)
   }
}

所以你可以做belong(yourStream, primeStream)

然而,这个解决方案不会比依次对每个数字的素数进行单独测试,在平方根处停止更为明显。特别是如果yourStream与素数相比快速增长,那么你必须徒劳地计算许多质数,只是为了跟上。如果没有理由怀疑你的流中的元素往往是素数或只有大的除数,那就更不用说了。

答案 1 :(得分:4)

  1. 您只需要阅读您的主流,直至sqrt(s)
  2. 当您从主要流中检索每个p时,请检查p是否均匀划分s
  3. 这将为您提供初步检查的试验分割方法。

答案 2 :(得分:1)

解决确定有序有限列表是否完全由有序但无限流的元素组成的一般问题:

最简单的方法是

candidate.toSet subsetOf infiniteList.takeWhile( _ <= candidate.last).toSet

但是如果候选人很大,那就需要很多空间而且它是O(n log n)而不是O(n)。 O(n)方式是

def acontains(a : Int, b : Iterator[Int]) : Boolean = {
  while (b hasNext) {
    val c = b.next
    if (c == a) {
       return true
    }
    if (c > a) {
       return false
    }
  }
  return false
}

def scontains(candidate: List[Int], infiniteList: Stream[Int]) : Boolean = {
  val it = candidate.iterator
  val il = infiniteList.iterator
  while (it.hasNext) {
     if (!acontains(it.next, il)) {
       return false
     }
  }
  return true
}

(顺便说一句,如果一些有用的灵魂可以提出一种更加可靠的方式来编写上述内容,我会很感激。)

修改

在评论中,不可估量的Luigi Plinge指出我可以写:

def scontains(candidate: List[Int], infiniteStream: Stream[Int]) = {
    val it = infiniteStream.iterator
    candidate.forall(i => it.dropWhile(_ < i).next == i) 
}