28

I was making a numbered list in LaTeX, but I was wondering whether I could make the numbers of the list prime numbers. So I'd like something like:

2. List item
3. List item
5. List item
7. List item

It is possible to do it by hand, but is it also possible to make it automatic?

4
  • If you provide an algorithm that calculates the prime numbers ;-)
    – user31729
    Apr 13 '16 at 18:19
  • 2
    See also The TeXbook, p. 218.
    – GuM
    Apr 13 '16 at 19:13
  • 4
    Is four a prime?
    – User
    Apr 13 '16 at 21:31
  • 1
    @User, Markdown is funny. If you start a line with n., then it'll initialise a numbered list starting from n, and interpret subsequent lines that start with numbers as part of that numbered list, incrementing each by 1 in the way that humans count, regardless of what that number was. Check the post's source if you're interested.
    – ymbirtt
    Apr 14 '16 at 7:34
21

I took a different approach, not using a list of primes but, rather, using pgfmath to find the primes instead. This was fun.

\documentclass{article}

\usepackage{pgfmath}
\usepackage{enumitem}

\newcounter{primecnt}

\newcommand{\nextprime}{%\
    \loop
        \stepcounter{primecnt}%
        \pgfmathsetmacro{\primeTF}{isprime(\theprimecnt)}%
    \ifnum\primeTF=0
        \repeat
}

\newlist{primeenumerate}{enumerate}{1}
\setlist[primeenumerate]{label=\theprimecnt.}

\makeatletter
\newenvironment{primeenum}{%
    \setcounter{primecnt}{0}%
    \def\item{%
        \nextprime
        \@inmatherr\item
        \@ifnextchar [\@item{\@noitemargtrue \@item[\@itemlabel]}%
    }%
    \begin{primeenumerate}
}{%
    \end{primeenumerate}
}
\makeatother

\begin{document}

\begin{primeenum}
\item one
\item two
\item three
\item four
\item five
\item six
\item seven
\item eight
\item nine
\item ten
\item eleven
\item twelve
\item thirteen
\item fourteen
\item fifteen
\item sixteen
\item seventeen
\end{primeenum}

\end{document}

The result:

Prime enumerate 2

Pointers on making this better code would be welcome...

1
  • Personally I prefer to use the build-in function like this.
    – Tawei
    Apr 14 '16 at 10:58
20

Here's an enumitem version with a special \AddEnumerateCounter output named \primeenum which can be used label={\primeenum*.} style.

Basically, it just applies \ifcase... \or...\fi and lists some prime numbers up to 59, but this can be extended of course.

\documentclass{article}

\usepackage{enumitem}


\makeatletter
\def\primeenum#1{\expandafter\@primenum\csname c@#1\endcsname}
\def\@primenum#1{%
  \ifcase#1
  \or
  2\or 3\or 5\or 7\or 11\or 13\or 17\or 19\or 23\or 29\or 31\or 37\or 41\or 43\or 47\or 53\or 59\else\@ctrerr\fi
}

\AddEnumerateCounter*{\primeenum}{\@primenum}{100}

\makeatother


\newlist{primenumerate}{enumerate}{1}
\setlist[primenumerate,1]{label={\primeenum*.}}


\begin{document}

\begin{primenumerate}
\item Foo
\item Bar
\item Is
\item Nice
\item Foo
\item Bar
\item Is
\item Nice
\item Foo
\item Bar
\item Is
\item Nice
\item Foo
\item Bar
\item Is
\item Nice
\end{primenumerate}


\end{document}

enter image description here

2
  • 1
    Very nice! But I’d end the \ifcase with ... 59\else \@ctrerr \fi.
    – GuM
    Apr 15 '16 at 16:31
  • @GustavoMezzetti: Thanks, that's a good suggestion. I've edited the code!
    – user31729
    Apr 15 '16 at 16:39
15

This answer takes Christian's excellent answer (and who deserves the credit for developing the basic structure) and tweaks it to make the input of new primes more streamlined. It uses the \getargsC macro of the readarray package to take a space-separated list and plunk the list into the macros \argi, \argii, \argiii, etc. in romannumeral fashion. This greatly simplifies the definition of \primenum to the following: \def\@primenum#1{\csname arg\romannumeral\the#1\endcsname}.

The result is the same.

\documentclass{article}
\usepackage{readarray, enumitem}
\makeatletter
\getargsC{2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53}
\def\@primenum#1{\csname arg\romannumeral\the#1\endcsname}
\def\primeenum#1{\expandafter\@primenum\csname c@#1\endcsname}
\AddEnumerateCounter*{\primeenum}{\@primenum}{100}
\makeatother
\newlist{primenumerate}{enumerate}{1}
\setlist[primenumerate,1]{label={\primeenum*.}}
\begin{document}
\begin{primenumerate}
\item Foo
\item Bar
\item Is
\item Nice
\item Foo
\item Bar
\item Is
\item Nice
\item Foo
\item Bar
\item Is
\item Nice
\item Foo
\item Bar
\item Is
\item Nice
\end{primenumerate}
\end{document}
2
  • Code stealer (;-) +1)
    – user31729
    Apr 13 '16 at 18:48
  • 11
    @ChristianHupfer Guilty as charged. I should have stolen from several people at once, and then I could call it "research". Apr 13 '16 at 18:48
8

Just for fun, a version that asks Pari-GP to increase the list of primes, using the function nextprime.

The final list is written out in the .aux file, so it can be recycled at initialization time. Note that shell escape is needed if the list has to be made larger. Of course, a working Pari-GP installation is needed.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\seq_new:N \g_primecount_list_seq % the primes to use
\int_new:N \g_primecount_max_int  % how many primes we need

% initialize
\seq_gset_from_clist:Nn \g_primecount_list_seq
 {
  2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53
 }

% if necessary, ask Pari-GP to make the list larger
\AtBeginDocument
 {
  \int_compare:nT { \seq_count:N \g_primecount_list_seq < \g_primecount_max_int }
   {
    \prg_replicate:nn { \g_primecount_max_int - \seq_count:N \g_primecount_list_seq }
     {
      \int_set:Nn \l_tmpa_int { \seq_item:Nn \g_primecount_list_seq { -1 } }
      \tl_set_from_file:Nnn \l_tmpa_tl { \endlinechar=-1 }
       { "|echo~'nextprime(\int_eval:n { \l_tmpa_int + 1 })'|gp~-q" }
      \seq_gput_right:NV \g_primecount_list_seq \l_tmpa_tl
     }
   }
 }

% the primeenum environment
\NewDocumentCommand{\maxprime}{m}
 {
  \int_compare:nT { #1 > \g_primecount_max_int }
   {
    \int_gset:Nn \g_primecount_max_int { #1 }
   }
 }

\DeclareExpandableDocumentCommand{\primecount}{m}
 { % #1 is the name of a counter
  \int_compare:nTF { \value{#1} > \seq_count:N \g_primecount_list_seq }
   {
    ???
   }
   {
    \seq_item:Nn \g_primecount_list_seq { \value{#1} }
   }
 }
\NewDocumentCommand{\checkprimes}{}
 {
  \int_compare:nT { \value{enumi} > \seq_count:N \g_primecount_list_seq }
   {
    \iow_shipout:cx { @auxout } { \maxprime { \int_to_arabic:n { \value{enumi} } } }
   }
 }
\cs_new_protected:Nn \primecount_dump_list:
 {
  \iow_now:cx { @auxout }
   {
    \buildprimelist { \seq_use:Nn \g_primecount_list_seq { , } }
   }
 }
\NewDocumentCommand{\buildprimelist}{m}
 {
  \seq_gset_from_clist:Nn \g_primecount_list_seq { #1 }
 }
\AtEndDocument
 {
  \primecount_dump_list:
  \cs_set_eq:NN \maxprime \use_none:n
  \cs_set_eq:NN \buildprimelist \use_none:n
 }
\ExplSyntaxOff

\NewDocumentEnvironment{primeenum}{}
 {\enumerate\renewcommand{\theenumi}{\primecount{enumi}}}
 {\checkprimes\endenumerate}

\begin{document}

\begin{primeenum}
\ExplSyntaxOn
\prg_replicate:nn { 199 } { \item X }
\ExplSyntaxOff
\item\label{Y} Y
\end{primeenum}

\ref{Y} is the 200th prime

\end{document}

enter image description here

Here's the contents of the .aux file, the list can be used also for the other presented implementations.

\relax 
\buildprimelist {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997,1009,1013,1019,1021,1031,1033,1039,1049,1051,1061,1063,1069,1087,1091,1093,1097,1103,1109,1117,1123,1129,1151,1153,1163,1171,1181,1187,1193,1201,1213,1217,1223}
\newlabel{Y}{{1223}{8}}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.