[Tex/LaTex] Customizing enumerate \item numbers

enumitemlists

I need to enumerate a nested list of items with two counters, so that consecutive items have numbers like 1-1, 1-2, 1-3, 1-4, then 2-1, 2-2, 2-3, 2-7, then 4-1, 4-3, 4-5, and so on.

The two tricky parts are that I need to be able to control…

  1. where the second counter rolls over (i.e. going from 1-4 to 2-1 in the example above), and

  2. where each counter has an increment greater than 1 (i.e. going from 2-3 to 2-7, or from 4-1 to 4-3 to 4-5, in the example above).

(My document is a solution manual for a book whose problems are numbered this way, but I don't yet have solutions for every one — so I need to jump the numbers in some spots. But I would very much like to avoid numbering \items manually, since that would defeat the purpose of enumerate.)

Edit Here's an MWE:

\documentclass[11pt,letterpaper]{article}
\usepackage{enumitem}
\begin{document}
\begin{enumerate}[label=\arabic*--\arabic*]
\item 1--1: This is easy.
\item 1--2: This is mostly easy but there's a twist.
\item 1--3: This is hard.
\item 2--1: This is very hard. % Step "major" number (1-->2).
\item 2--5: This is nearly impossible. % Discontinuous step in "minor" number (1-->5).
\end{enumerate}
\end{document}

Instead of the desired problem numbers, this produces 1–1, 2–2, 3–3, etc.

Best Answer

Here is a similar approach except that I override \item so that you can use it to change the problem counters. For example,

\item[3-2]

will set the current item number to 3-2 after which \item will produce 3-3, 3-4, ... until the next \item with an optional argument.

I have used the enumitem package to wrap the code into a new problems environment, which also means that you can use all of the usual enumitem formatting etc. For an extended example,

\begin{problems}[nosep]
  \item bla
  \item bla
  \item bla
  \item[1-8] bla
  \item bla
  \item[2-1] bla
  \item bla
  \item[2-4] bla
  \item bla
  \item[3-2] bla
  \item bla
\end{problems}

will produce

enter image description here

Here is the full code:

\documentclass{article}
\usepackage{enumitem}

\let\realItem\item
\newcounter{problem}
    \setcounter{problem}{1}
\newcounter{subproblem}[problem]
\renewcommand\thesubproblem{\arabic{problem}-\arabic{subproblem}}

\def\SetProblemCounters#1-#2!!{% extract new problem and subproblem numbers
  \setcounter{problem}{#1}
  \setcounter{subproblem}{\numexpr#2-1\relax}% so that \ref will work properly
}
\newcommand\myItem[1][]{%
   \if\relax\detokenize{#1}\relax\else\SetProblemCounters#1!!\fi%
   \refstepcounter{subproblem}%
   \realItem[\thesubproblem]%
}

\newlist{problems}{enumerate}{1}
\setlist[problems]{before=\let\item\myItem}
\begin{document}

\begin{problems}[nosep]
  \item bla
  \item bla
  \item bla
  \item[1-8] bla
  \item bla
  \item[2-1] bla
  \item bla
  \item[2-4] bla
  \item bla
  \item[3-2] bla
  \item bla
\end{problems}

\end{document}

Some explanation of the code

  • The macro \SetProblemCounters is defined by \def\SetProblemCounters#1-#2!!. What this means is that it expects two arguments where #1 is what appears between \SetProblemCounters and a- and #2 is what appears between the - and !!. If you try to use it without following this syntax an error error results. The only reason why - and !! are part of the definition of \SetProblemCounters is to give an easy way to extract the value of problem and subproblem. As explained below, this is achieved using \myItem. (You could use anything you want instead of !!, provided you also change the !! in \myItem.)
  • The before=\let\item\myItem inside the \setlist{...} for the problems environment says that when you are inside a problems environment then \item is really the macro \myItem
  • By definition \myItem takes an optional argument, which by default is empty. The line \if\relax\detokenize{#1}\relax is the "standard way" to check to see if #1 is empty. When it is non-empty, then \myItem "gives" #1!! to \SetProblemCounters -- in particular, note that it adds two exclamation marks!! So, inside the problems environment, if you type \item[3-7] then this becomes \myItem[3-7] and then \SetProblemCounters3-7!!. Consequently, \SetProblemCounters ends up with #1 equal to 3 and #2 equal to 7. (If you type \item[2] inside a problems environment then you will get an error because \SetProblemCounters expects to find a -.)
  • What \SetProblemCounters actually does is set the problem counter equal to #1 and the subproblem counter equal to #2-1, which is does using \numexpr (the \relax tells \numexpr where to stop). The \myItem macro always increments the the subproblem counter, using \refstepcounter{subproblem}, with the result that \label{...} and \ref{...} will now have the expected values.
  • Finally, the line \let\realItem\item makes a "copy" of the original \item command. This lets \myItem use the "real" item, via \realItem[\thesubproblem], because when \myItem is being used the macro \item is actually equal to \myItem.
Related Question