14

I would like to have an enumerate list, with the numbers expressed in unary. That is, "1" would be represented as , "3" as •••, and "8" as •••••|•••.

I'm able to print the dots already, and that's working fine:

\newcommand{\xxdot}{\textbullet} % The dot character to use
\newcounter{loopcntr} % A one-off counter for \forloop

\newcommand{\xxdots}[1]{% Print #1 dots in a row
    \ifthenelse{#1>5}{% If there are more than five, break them into groups
        \xxdots{5}\textpipe\xxdots{\number\numexpr#1-5\relax}% By printing five, then a pipe, then the rest
    }{% Otherwise, just print that many dots
        \forloop{loopcntr}{0}{\value{loopcntr}<#1}{\xxdot}%
    }%
}
\newcommand{\xdots}[1]{\textnormal{\xxdots{#1}}} % Wrap it in textnormal style

However, I have no idea how to make enumerate use this. Based on this answer, I tried redefining \theenumi:

\renewcommand\theenumi{\xdots{\arabic{enumi}}}

But this went badly wrong:

! Illegal parameter number in definition of \@currentlabel.
<to be read again> 
                   1
l.376 ^^I\item My text here ...
You meant to type ## instead of #, right?
Or maybe a } was forgotten somewhere earlier, and things
are all screwed up? I'm going to assume that you meant ##.

How can I apply my unary-printing code to the enumerate label?

EDIT: Based on this answer, I tried this:

\newcommand*\unary[1]{\expandafter\@unary\csname c@#1\endcsname}
\newcommand*\@unary[1]{\xdots{\the\numexpr#1\relax}}

And it seems to work! As in, this produces the correct output:

\newcounter{test}
\setcounter{test}{8}
\unary{test}

However, the MWE still throws a bunch of errors.

MWE follows:

\documentclass{article}

\usepackage{forloop}
\usepackage{tipa}
\usepackage[T1]{fontenc}

\newcommand{\xxdot}{\textbullet} % The dot character to use
\newcounter{loopcntr} % A one-off counter for \forloop

\newcommand{\xxdots}[1]{% Print #1 dots in a row
    \ifthenelse{#1>5}{% If there are more than five, break them into groups
        \xxdots{5}\textpipe\xxdots{\number\numexpr#1-5\relax}% By printing five, then a pipe, then the rest
    }{% Otherwise, just print that many dots
        \forloop{loopcntr}{0}{\value{loopcntr}<#1}{\xxdot}%
    }%
}
\newcommand{\xdots}[1]{\textnormal{\xxdots{#1}}} % Wrap it in textnormal style

\makeatletter
\newcommand*\unary[1]{\expandafter\@unary\csname c@#1\endcsname}
\newcommand*\@unary[1]{\xdots{\the\numexpr#1\relax}}
\makeatother

%\renewcommand\theenumi{\unary{enumi}} % This crashes and burns

\begin{document}

Unary works normally: \xdots{1}, \xdots{3}, \xdots{8}.

It even works with a counter.

\newcounter{test}
\setcounter{test}{8}
\unary{test}

But in a list:

\begin{enumerate}
    \item My text here my text here
    \item More text more text
    \item Even more text
\end{enumerate}

\end{document}
  • Are you aware of this question? – user121799 May 20 at 3:44
  • @marmot I was not, but it seems to offer good solutions! – Draconis May 20 at 4:12
14

The enumitem package is your friend. You can define a new list style, which I have called unerate, and then make this list style use your \unary code. To achieve this it is enough to add the following lines to your code:

\let\realItem\item
\newcommand\unerateItem{\refstepcounter{uneratei}\realItem[\unary{uneratei}]}
\usepackage{enumitem}
\newlist{unerate}{enumerate}{1}
\setlist[unerate]{label=\alph*, before=\let\item\unerateItem }

So this redefines \item to be \unerateItem and this, in turn, uses the "real" \item with \unary applied to the list environment counter, which is called uneratei. With this in place, the code

\begin{unerate}
    \item My text here my text here
    \item More text more text
    \item Even more text
    \item Even more text
    \item Even more text
    \item Even more text
    \item Even more text
    \item Even more text
\end{unerate}

produces:

enter image description here

Here is the full code:

\documentclass{article}

\usepackage{forloop}
\usepackage{tipa}
\usepackage[T1]{fontenc}

\newcommand{\xxdot}{\textbullet} % The dot character to use
\newcounter{loopcntr} % A one-off counter for \forloop

\newcommand{\xxdots}[1]{% Print #1 dots in a row
    \ifthenelse{#1>5}{% If there are more than five, break them into groups
        \xxdots{5}\textpipe\xxdots{\number\numexpr#1-5\relax}% By printing five, then a pipe, then the rest
    }{% Otherwise, just print that many dots
        \forloop{loopcntr}{0}{\value{loopcntr}<#1}{\xxdot}%
    }%
}
\newcommand{\xdots}[1]{\textnormal{\xxdots{#1}}} % Wrap it in textnormal style

\makeatletter
\newcommand*\unary[1]{\expandafter\@unary\csname c@#1\endcsname}
\newcommand*\@unary[1]{\xdots{\the\numexpr#1\relax}}
\makeatother

\let\realItem\item
\newcommand\unerateItem{\refstepcounter{uneratei}\realItem[\unary{uneratei}]}
\usepackage{enumitem}
\newlist{unerate}{enumerate}{1}
\setlist[unerate]{label=\alph*, before=\let\item\unerateItem }

\begin{document}

  \begin{unerate}
    \item My text here my text here
    \item More text more text
    \item Even more text
    \item Even more text
    \item Even more text
    \item Even more text
    \item Even more text
    \item Even more text
  \end{unerate}

\end{document}

You can now use enumitem to style these environments to your heart's content.

The code above will not let you nest unerate environments. If this is required let me know and I will update it - it's not difficult, but requires a little extra work.

  • Perfect! I'll wait a bit longer before accepting, but this seems to fulfill my needs perfectly. (As you surmised, I won't need to nest these environments.) – Draconis May 20 at 4:10
  • Actually, one thing to note: this does not work if the hyperref package is included first. It works fine if hyperref is included later, though. – Draconis May 20 at 4:34
  • 1
    @DraconisAccording to its manual, you should always load hyperref last :) – Andrew May 20 at 4:55
  • I wonder how you read unerate ... – L. F. May 20 at 10:35
16

I recycled this code and slightly extended it to get

\documentclass{article}
\usepackage{pgffor}
\newcommand{\nbullets}[2][\textbullet]{%
\foreach \X [evaluate=\X as \Y using {int(mod(\X,5))}]in {1,...,#2}
{\ifnum\X>1%
\ifnum\Y=1%
$\vert$\fi%
\fi%
#1}}
\begin{document}
\renewcommand{\labelenumi}{\nbullets{\value{enumi}}}
\begin{enumerate}
 \item first
 \item second
 \item third
 \item fourth
 \item fifth
 \item sixth
 \item seventh
 \item last 
\end{enumerate}

Nestable:
\renewcommand{\labelenumii}{\nbullets[*]{\value{enumii}}}
\begin{enumerate}
 \item first
 \item second
 \begin{enumerate}
  \item a
  \item b
  \item c
  \item d
  \item e
  \item f
 \end{enumerate}
 \item third
 \item fourth
 \item fifth
 \item sixth
 \item seventh
 \item last 
\end{enumerate}
\end{document}

enter image description here

A version for Stefan. (\TCS is essentially from here.)

\documentclass{article}
\usepackage{tikz}
\newcommand{\nbullets}[2][\textbullet]{%
\foreach \X [evaluate=\X as \Y using {int(mod(\X,5))}]in {1,...,#2}
{\ifnum\X>1%
\ifnum\Y=1%
$\vert$\fi%
\fi%
#1}}
\newcommand{\TCS}[2][]{\begin{tikzpicture}[baseline,#1]
\foreach \X [evaluate=\X as \Y using {int(mod(\X,5))}]in {1,...,#2}
{\ifnum\Y=0
\draw (\X*0.5ex+0.3ex,0) -- ++(-2.8ex,2ex);
\else
\draw (\X*0.5ex+0.3ex,0) -- ++(0,2ex);
\fi}
\end{tikzpicture}}
\begin{document}
\renewcommand{\labelenumi}{\TCS{\value{enumi}}}
\renewcommand{\labelenumii}{\nbullets{\value{enumii}}}
\begin{enumerate}
 \item first
 \item second
 \begin{enumerate}
  \item a
  \item b
  \item c
  \item d
  \item e
  \item f
 \end{enumerate}
 \item third
 \item fourth
 \item fifth
 \item sixth
 \item seventh
 \item last 
\end{enumerate}
\end{document}

enter image description here

  • +1 How would you create an Enumeration with Tally marks in this way? – Stefan May 20 at 8:58
  • 1
    @Stefan This answer starts with "something like this?" ;-) – user121799 May 20 at 12:19
  • 1
    Thank you both for the link and your extended answer. – Stefan May 20 at 13:59
10

Here's an expandable \unifive macro:

\documentclass{article}
\usepackage{xparse,enumitem,tipa}

\usepackage{showframe}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\unifive}{m}
 {% #1 should be an integer
  \draconis_unifive:n { #1 }
 }

\cs_new:Nn \draconis_unifive:n
 {
  \int_compare:nTF { #1 > 5 }
   {
    \unifivefive
    \draconis_unifive:e { \int_eval:n { #1 - 5 } }
   }
   {
    \prg_replicate:nn { #1 } { \unifiveone }
   }
 }
\cs_generate_variant:Nn \draconis_unifive:n { e }

\NewDocumentCommand{\unifivefive}{}
 {
  \unifiveone\unifiveone\unifiveone
  \unifiveone\unifiveone\unifivebar
 }

\NewDocumentCommand{\unifiveone}{}{\textbullet}
\NewDocumentCommand{\unifivebar}{}{\textpipe}

\ExplSyntaxOff

\makeatletter
\newcommand{\unifivecount}[1]{\expandafter\@unifivecount\csname c@#1\endcsname}
\newcommand{\@unifivecount}[1]{\unifive{#1}}
\AddEnumerateCounter{\unifivecount}{\@unifivecount}{\unifive{10}}
\makeatother

\newlist{unerate}{enumerate}{1}
\setlist[unerate]{label=\unifivecount*,leftmargin=*}

\begin{document}

\begin{unerate}
  \item My text here my text here
  \item More text more text
  \item Even more text
  \item Even more text
  \item Even more text
  \item Even more text
  \item Even more text
  \item Even more text
  \item Even more text
  \item Even more text
\end{unerate}

\unifive{42}

\end{document}

enter image description here

6

You don't need explicit loops to generate a number of bullets

enter image description here

\documentclass{article}

\renewcommand\labelenumi{\theenumi\space}
\renewcommand\theenumi{\expandafter\zzm\romannumeral\the\value{enumi}000\relax}

\def\zzm#1{\if m#1\textbullet\expandafter\zzm\fi}

\begin{document}

\begin{enumerate}
    \item My text here my text here
    \item More text more text
    \item Even more text
\end{enumerate}

\end{document}

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.