How can I make this code more functional in Javascript?

2

This code solves the problem of finding the num prime between 0 and 10,000:

  function PrimeMover(num) { 

  var counter = 0;
  var primes = [];

  for (var i=2; i<=10000; i++){

    for (var j = 2; j<i; j++){

      if (i%j===0) { counter++ };

    }

    if (counter === 0) { primes.push(i) };
    counter = 0;

  }

  return primes[num-1]

}

I would like some help on how to solve the problem using Javascript functional programming.

    
asked by anonymous 23.06.2015 / 23:35

3 answers

2

The question ends up involving more math than programming itself, as I am no expert in mathematics I will try to explain in the simplest and lay way.

How do you find out if a number is prime ? Simple, it can only be divisible by 1 by itself.

Instead of following this rule why not look for numbers that are divisible by any number other than 1 and itself? From here you already eliminate half of the numbers up to their value.

Your possible divisors will have the following formula:

To implement:

function PrimeMover(num) {
    var encontrados = 1;
    var primos = [2];

    // já temos o [2] então posso partir do [3]
    var numero = 3; 

    // vai rodar quantas vezes forem necessárias até encontrar o enésimo número
    while (encontrados < num) {
        var numeroPrimo = true;

        // implementação da nossa regra, procura pelos valores até metade
        for (i=2; i <= Math.sqrt(numero); i++) {
            if (numero % i == 0) {
                numeroPrimo = false;
                break;
            }
        }

        // se for numero primo adiciona na lista e incrementa os encontrados pra saber quando parar
        if (numeroPrimo) {
            primos.push(numero);
            encontrados++;
        }
        numero++;
    }

    return primos[num-1];
}
    
24.06.2015 / 00:21
5

The suggestion I would make is to actually erastostenes sieve instead of a "trial division" algorithm.

function PrimeMover(num) { 

  var N = 10000;
  var isPrime = [];
  isPrime[0] = false;
  isPrime[1] = false;
  for (var i=2; i <= N; i++){
      isPrime[i] = true;
  }

  var primes = [];
  for (var i=2; i <= N; i++){
    if(!isPrime[i]) continue;

    primes.push(i);
    for (var j = 2*i; j <= N; j += i){
      isPrime[i] = false;
    }
  }

  return primes[num-1]
}

This algorithm is much more efficient than what you are using. It has O(N log log N) complexity while the algorithm testing the divisors has O((N/log n)^2) complexity

As for making the code more functional, I do not know if it's worth it. It is not trivial to write the sieve of erastostenes without using a vector and most of the functional algorithms for calculating cousins that are out there are inefficient as the code of your question: link

    
23.06.2015 / 23:54
1

The main concepts of the functional paradigm are high order functions (functions that receive other functions as arguments) and absence of side effects . Programs are written as function comps, rather than sequential procedures.

To solve this problem, we can define the desired result as the list of numbers that passes a primality test .

We started by generating a list (an array, actually) of candidates:

var candidatos = [];
for (var i = 2; i <= 10000; i++) {
    candidatos.push(i);
}

And, of these candidates, we want to separate the passers in a primality test. We defined our test:

var teste_primo = function (n) {
    for (var i=2; i*i <= n; i++)
    if (n%i == 0)
        return false;
    return true;
}

And, finally, we filter the candidates who pass the test:

candidatos.filter(teste_primo)

Note that the filter function takes another function as its argument - our primality test. It applies the test to the numbers and returns a new array containing only those passing the test.

We can use the same function, for example, to separate the pairs:

candidatos.filter (function (n) {return n % 2 == 0})

(Note that I defined the function at the same time that I passed it as a parameter - I do not need to give it a name if I use it only once, which is common in the functional paradigm.)

It is important to note that, except for the declaration of our list of candidates, none of our functions have generated side effects (change of external variables, etc.). We define functions and compose these functions to get the result as a return.

Another consequence is that if we want to change our primality test to something more efficient, we just need to provide another function instead of test_primo . The primality test is isolated from the rest of the program logic.

Finally, the filter function is already implemented in the language, but we could implement our own version. What it does is to get an array, a test, and return an array with the elements that pass the test:

var meu_filter = function (arr, teste){
    var saida = []
    for (var i = 0; i <= arr.length; i++)
    if (teste(arr[i])){
        saida.push(i)
    }
    return saida
}

Testing:

< meu_filter(candidatos,teste_primo)
> Array [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 1219 mais… ]
    
30.08.2015 / 02:31