Let's say I want to answer the question "what are the first 400 palindromic prime numbers?"
The first approach that comes to my mind from the set of languages that I know is to use some sort of lazy list materialization, a la IEnumerable
(and yield
) in C#, generators in Python, or sequence
blocks in F#.
For example, in C#:
PrimesEnumerator().Where(n => n.ToString() == n.ToString().Reverse()).Take(400);
This would cause the PrimesGenerator to be pumped for primes long enough for the Where()
clause to find enough numbers that meet the requirement for Take()
to meet its quota.
The best I've come up with in Mathematica is something like:
i = 1; results = List[];
While[Length[results] != 400,
If[IntegerDigits[Prime[i]] == Reverse[IntegerDigits[Prime[i]]],
results = Append[results,Prime[i]]];
i = i + 1]
It surprises me that I end up writing in such an imperative style in Mathematica. Am I missing something that would let me write this entirely functionally? Maybe even with lazy lists?
Update: I took inspiration from WReach's work of art answer, and made a package that took his ideas and expanded them into a broad, general solution for lazy data in Mathematica. I describe its usage in an answer below.
For[i = 1; k = 1; results = {}, k <= 300, i++, If[IntegerDigits[Prime[i]] == Reverse[IntegerDigits[Prime[i]]], results = {results, Prime[i]}; k++]]; Flatten[results]
. $\endgroup$Range[]
you need to iterate through". It seems, at least in the general case, that there's no great way to avoid that. Maybe I need to write a "Lazy Generators" package for Mathematica. $\endgroup$results = {results, Prime[i]}; Flatten[results]
instead ofresults = Append[results,Prime[i]]
? I'm guessing it's to defer reallocation costs forresults
? $\endgroup$