Simple top-level solution
Here is a simplistic completely top-level code:
ClearAll[happyQ];
happyQ[n_] :=
Block[{appeared},
appeared[_] = False;
Take[
NestWhileList[
Total[IntegerDigits[#]^2] &,
n,
(! appeared[#] && (appeared[#] = True)) &
], -2] == {1, 1}];
Clear[happyPrimeN];
happyPrimeN[n_] :=
Module[{m = 0, pctr = 0},
While[m < n, If[happyQ@Prime[++pctr], m++]];
{pctr, Prime[pctr]}
];
Using this, we get for example:
happyPrimeN/@Range[5]
(* {{4,7},{6,13},{8,19},{9,23},{11,31}} *)
And for 2000th happy prime, we have:
happyPrimeN[2000] // AbsoluteTiming
(* {1.5693359, {12814, 137653}} *)
which is not particularly fast, but probably ok. I am sure that there are faster solutions though.
Java solution with memoization
One thing I want to mention here: I had about 10 iterations of this one before I finally optimized it, and when I did, I looked closer at @Rojo's solution and found that I just arrived to a Java port of it. So, while I did it independently, I just want to stress that the following code does not contain new or better ideas than those used by @Rojo for his beautiful solution.
Ok, so:
Load the Java reloader
Compile the following class:
JCompileLoad@"import java.util.*;
public class HappyPrimes{
public Map<Integer,Boolean> happy = new HashMap<Integer,Boolean>(10000);
private int max;
public HappyPrimes(int max){
this.max = max;
happy.put(1,true);
}
public int getDigitsSqSum(int num){
int result = 0;
while(num>0){
int dig = num % 10;
result+=dig*dig;
num /=10;
}
return result;
}
private boolean isHappy(int num){
if(happy.containsKey(num)){
return happy.get(num);
}
happy.put(num,false);
boolean result = isHappy(getDigitsSqSum(num));
happy.put(num,result);
return result;
}
public int[] currentMaxHappyPrime(int[] primes,
int startPrime, int currentMax){
int done = 0;
int i = 0;
for( ; i< primes.length ; i++){
if(isHappy(primes[i])&& ++currentMax == max){
done = 1;
break;
}
}
startPrime+=i;
return new int[]{startPrime,currentMax,done};
}
}";
The "top-level" function follows:
ClearAll[happyPrimeNJ];
happyPrimeNJ[n_, chunk_: 5000] :=
JavaBlock[
With[{o = JavaNew["HappyPrimes", n]},
{#, Prime[#]} &@(First[#] + 1) &@
NestWhile[
o@currentMaxHappyPrime[
Prime[Range[First@# + 1, First@# + chunk]], #[[1]], #[[2]]
] &,
{0, 0, 0},
Last@# != 1 &]
]
];
What happens here is that I use Mathematica to generate primes in chunks. I send those to Java and count the number of happy primes in a given chunk. When I get enough, I stop and return the prime index. At intermediate steps, I return a list of 3 numbers: current total number of processed primes, current total number of happy primes among those, and a flag telling me whether or not I should continue.
Here is how we use it:
happyPrimeNJ[50000]//AbsoluteTiming
{1.2324219,{365523,5263169}}
My benchmarks show that it is systematically several times (up to 10) faster than @Rojo's version, but we don't see a dramatic speed-up as in some other cases, since @Rojo very cleverly uses the language, and Mathematica hash tables (DownValues) are pretty efficient. Also, for (relatively) small numbers of happy primes (such as 2000), the speedup is not so apparent since there is a constant overhead of Java calls which is of the same order as the total time it takes to process those.
Summary and conclusions
The first method I presented is relatively slow, being the most straightforward. The second one, based on Java, is fast. However, it does not really compete with the elegant and terse solution of @Rojo, and moreover, is more or less a direct port of it to Java (even though I arrived at it mostly independently).