Find prime numbers using Scala. Help me to improve

前端 未结 10 952
北荒
北荒 2020-12-01 22:31

I wrote this code to find the prime numbers less than the given number i in scala.

def findPrime(i : Int) : List[Int] = i match {
    case 2 => List(2)
           


        
相关标签:
10条回答
  • 2020-12-01 22:35

    Here's a functional implementation of the Sieve of Eratosthenes, as presented in Odersky's "Functional Programming Principles in Scala" Coursera course :

      // Sieving integral numbers
      def sieve(s: Stream[Int]): Stream[Int] = {
        s.head #:: sieve(s.tail.filter(_ % s.head != 0))
      }
    
      // All primes as a lazy sequence
      val primes = sieve(Stream.from(2))
    
      // Dumping the first five primes
      print(primes.take(5).toList) // List(2, 3, 5, 7, 11)
    
    0 讨论(0)
  • 2020-12-01 22:35
    object Primes {
      private lazy val notDivisibleBy2: Stream[Long] = 3L #:: notDivisibleBy2.map(_ + 2)
      private lazy val notDivisibleBy2Or3: Stream[Long] = notDivisibleBy2
          .grouped(3)
          .map(_.slice(1, 3))
          .flatten
          .toStream
      private lazy val notDivisibleBy2Or3Or5: Stream[Long] = notDivisibleBy2Or3
          .grouped(10)
          .map { g =>
            g.slice(1, 7) ++ g.slice(8, 10)
          }
          .flatten
          .toStream
    
      lazy val primes: Stream[Long] = 2L #::
          notDivisibleBy2.head #::
          notDivisibleBy2Or3.head #::
          notDivisibleBy2Or3Or5.filter { i =>
            i < 49 || primes.takeWhile(_ <= Math.sqrt(i).toLong).forall(i % _ != 0)
          }
    
      def apply(n: Long): Stream[Long] = primes.takeWhile(_ <= n)
    
      def getPrimeUnder(n: Long): Long = Primes(n).last
    }
    
    0 讨论(0)
  • 2020-12-01 22:36

    @mfa has mentioned using a Sieve of Eratosthenes - SoE and @Luigi Plinge has mentioned that this should be done using functional code, so @netzwerg has posted a non-SoE version; here, I post a "almost" functional version of the SoE using completely immutable state except for the contents of a mutable BitSet (mutable rather than immutable for performance) that I posted as an answer to another question:

    object SoE {
      def makeSoE_Primes(top: Int): Iterator[Int] = {
        val topndx = (top - 3) / 2
        val nonprms = new scala.collection.mutable.BitSet(topndx + 1)
        def cullp(i: Int) = {
          import scala.annotation.tailrec; val p = i + i + 3
          @tailrec def cull(c: Int): Unit = if (c <= topndx) { nonprms += c; cull(c + p) }
          cull((p * p - 3) >>> 1)
        }
        (0 to (Math.sqrt(top).toInt - 3) >>> 1).filterNot { nonprms }.foreach { cullp }
        Iterator.single(2) ++ (0 to topndx).filterNot { nonprms }.map { i: Int => i + i + 3 }
      }
    }
    
    0 讨论(0)
  • 2020-12-01 22:41

    As schmmd mentions, you want it to be tail recursive, and you also want it to be lazy. Fortunately there is a perfect data-structure for this: Stream.

    This is a very efficient prime calculator implemented as a Stream, with a few optimisations:

    object Prime {
      def is(i: Long): Boolean =
        if (i == 2) true
        else if ((i & 1) == 0) false // efficient div by 2
        else prime(i)
    
      def primes: Stream[Long] = 2 #:: prime3
    
      private val prime3: Stream[Long] = {
        @annotation.tailrec
        def nextPrime(i: Long): Long =
          if (prime(i)) i else nextPrime(i + 2) // tail
    
        def next(i: Long): Stream[Long] =
          i #:: next(nextPrime(i + 2))
    
        3 #:: next(5)
    
      }
    
        // assumes not even, check evenness before calling - perf note: must pass partially applied >= method
      def prime(i: Long): Boolean =
        prime3 takeWhile (math.sqrt(i).>= _) forall { i % _ != 0 }
    }
    

    Prime.is is the prime check predicate, and Prime.primes returns a Stream of all prime numbers. prime3 is where the Stream is computed, using the prime predicate to check for all prime divisors less than the square root of i.

    0 讨论(0)
  • 2020-12-01 22:41

    A sieve method is your best bet for small lists of numbers (up to 10-100 million or so). see: Sieve of Eratosthenes

    Even if you want to find much larger numbers, you can use the list you generate with this method as divisors for testing numbers up to n^2, where n is the limit of your list.

    0 讨论(0)
  • 2020-12-01 22:45
    def primeNumber(range: Int): Unit ={
        val primeNumbers: immutable.IndexedSeq[AnyVal] =
          for (number :Int <- 2 to range) yield {
            val isPrime = !Range(2, Math.sqrt(number).toInt).exists(x => number % x == 0)
            if(isPrime)  number
          }
        for(prime <- primeNumbers) println(prime)
      }
    
    0 讨论(0)
提交回复
热议问题