1

Problem:

I need to create a Scala program which uses Stream class and finds n-th prime number from interval [i, j] (whereas 1 <= i < j).

More information:

I am completely new in Scala but I've looked for various examples on how to find primes in Scala using Stream. None of them helped me to achieve my goal.

I can't seem to understand how to make stream a finite list in interval [i, j] and how to take n-th prime number from that interval.

My code so far:

def primeStream(args: Array[String], s: Stream[Int]): Stream[Int] =
        Stream.cons(s.head, primeStream(args,s.tail filter {_ % s.head != 0 }))

if (args(0).toInt < 1) {
        println("Entered parameter i does not meet requirements 1<=i<j (1<=" + args(0) + "<" + args(1) + ")")
        sys.exit(1)
} else if (args(1).toInt < args(0).toInt) {
        println("Entered parameter j does not meet requirements 1<=i<j (1<=" + args(0) + "<" + args(1) + ")")
        sys.exit(1)
}

val primes = primeStream(args,Stream.from(args(0).toInt)) // start from i element

primes take args(1).toInt foreach println //Take j elements

Any help would be appreciated!

SOLUTION:

def primeStream(s: Stream[Int]): Stream[Int] =
        Stream.cons(s.head, primeStream(s.tail filter {_ % s.head != 0 }))

if (args(0).toInt < 1) {
        println("Entered parameter i does not meet requirements 1<=i<j (1<=" + args(0) + "<" + args(1) + ")")
        sys.exit(1)
} else if (args(1).toInt < args(0).toInt) {
        println("Entered parameter j does not meet requirements 1<=i<j (1<=" + args(0) + "<" + args(1) + ")")
        sys.exit(1)
} else if (args(0).toInt == 1) {
        println("1 is not a prime by definition!") 
        sys.exit(1)  // if args(0) is 1 then function hangs up - didn't come up with a better solution for this
}

val primes = primeStream(Stream.from(args(0).toInt)) // get primes starting from given parameter

println(primes.takeWhile( _ < args(1).toInt).take(args(2).toInt).last) // get n-th prime and print it out
Alexander Gusev
  • 295
  • 1
  • 9

2 Answers2

1

You just need to have your stream generate values while a certain condition holds:

primes takeWhile(_ < j) take n foreach println

and, of course, you need to get the primeStream function right.

For the algorithmic part, you'd better search on stackoverflow:

Community
  • 1
  • 1
metaphori
  • 2,681
  • 1
  • 21
  • 32
  • Thanks! This now gives me interval [i; j] from which I should take specific n-th element. How do I take this n-th element? I assume, that I pass 3 arguments: i j k – Alexander Gusev Dec 04 '15 at 22:08
  • You need to take the last element in the resulting stream, i.e., `primes takeWhile(_ < j) take n last` – metaphori Dec 04 '15 at 22:12
  • Hmm, I feel a bit dumb now. Why last? For example, I have a list of primes in interval `[2; 13]` and I want to take 5-th (n-th) element which is 11 [2,3,5,7,**11**,13]. How do I check that 11 is 5-th element? – Alexander Gusev Dec 04 '15 at 22:21
  • It is the `last` in what you get *after* you take `n` elements. – metaphori Dec 04 '15 at 22:23
  • Nope, I can't get it to work. If I run it like this: `primes takeWhile( _ < args(1).toInt) take args(2).toInt last` then there is a warning stating _"there was one feature warning; re-run with -feature for details"_. If I leave it like this: `primes takeWhile( _ < args(1).toInt) take args(2).toInt last println` then it shows error _"Int does not take parameters"_. Could you elaborate, please? – Alexander Gusev Dec 04 '15 at 22:56
  • You can remove the warning just by avoiding the "operator syntax": `primes.takeWhile(_ < j).take(n).last` – metaphori Dec 04 '15 at 23:15
1

Is this a learning exercise, or do you need this in production? For the latter, I would suggest using spire.math.prime.stream from the spire library. It is using a Segmented Stream of Eratosthenes implementation which is probably better than what you will come up with yourself in a short time. It also uses arbitrary precision integers, so it works for numbers larger than 2^64.

scala> import spire.math._
import spire.math._

scala> prime.stream.drop(10).take(10).toArray
res16: Array[spire.math.SafeLong] = Array(31, 37, 41, 43, 47, 53, 59, 61, 67, 71)
Rüdiger Klaehn
  • 12,445
  • 3
  • 41
  • 57
  • Yes, it is a learning exercise. Thank you very much for your comment - it indeed looks easier and better but I will go with my solution. – Alexander Gusev Dec 05 '15 at 19:58
  • I found a problem that if I change interval from `[2,..]` to something greater than 2, e.g. `[20,30]` and execute `scala prime.scala 20 30 2` it returns 21 but it should return 29 as it is second prime in this specific interval. I tried to manipulate with `takeWhile` to achieve needed result but so far no luck. What should I change in my program in order to achieve that? Can you please help? – Alexander Gusev Dec 10 '15 at 19:11