4

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.

  • 1
    Welcome to TeX.SX! With enumitem and custom counters you are in the right direction, but please help us help you by providing a minimal working example (MWE). – TeXnician Dec 4 '17 at 6:04
  • Welcome to TeX.SX. When you post a question, you are expected to provide a "Minimal Working Example" (MWE) that starts with \documentclass, includes all relevant \usepackage commands, ends with \end{document} and compiles without errors, even if it does not produce your desired output. – Sandy G Dec 4 '17 at 6:06
  • @TeXnician, Sandy G - Sorry about the omission. MWE added above. And two folks have already posted perfect, if non-obvious (to me at least) responses. Thanks so much. – Jim Dec 4 '17 at 18:02
4

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.
  • This is (also) exactly what I was looking for, but there's a fair bit going on in your code that I'll need to study carefully. One thing I don't understand is the syntax of the SetProblemCounters definition -- It looks like it expects two numerical arguments separated by a dash, but when invoked in the myItem block that follows, there's only a single argument (#1). Also, what's the meaning of the double exclamation point? (That feature is particularly hard to Google ...). – Jim Dec 4 '17 at 17:36
  • @Jim I'll add some more explanation – Andrew Dec 4 '17 at 20:17
  • @jim I have also changed the code a little so that it now defines and uses \thesubproblem. I realised that this was necessary in order have \label{...} and `\ref{...} work as advertised. – Andrew Dec 4 '17 at 20:36
5

Something like this?

enter image description here

Use \stepcounter or \refstepcounter to increment outernum; use \stepcounter, \refstepcounter, or \addtocounter{innernum}{<n>} to increment innernum.

\documentclass{article}
%% Define two new counters
\newcounter{outernum}
\newcounter{innernum}[outernum]

%% Create a custom enumerated environment
\usepackage{enumitem}
\newlist{compenum}{enumerate}{1}
\setlist[compenum]{label=\arabic{outernum}-\arabic{innernum}}

%% Modify behavior of \item inside 'compenum' env.
\usepackage{etoolbox}
\AtBeginEnvironment{compenum}{%
  \let\origitem\item
  \renewcommand\item{\refstepcounter{innernum}\origitem}}

\begin{document}

\begin{compenum}
\stepcounter{outernum}
\item bla
\item bla
\item bla
\item bla

\stepcounter{outernum}
\item bla
\item bla
\item bla
\addtocounter{innernum}{3}
\item bla

\stepcounter{outernum}
\stepcounter{outernum}
\item bla
\addtocounter{innernum}{1}
\item bla
\addtocounter{innernum}{1}
\item bla
\end{compenum}

\end{document}
  • Thanks! This is exactly what I was looking for. I had already tried \stepcounter, but neglected to define inner and outer counters explicitly. Nice! – Jim Dec 4 '17 at 16:41
  • Rather than use \AtBeginEnvironment you can use\setlist[compenum]{before=...} to run some code at the start of your compenum environment. – Andrew Dec 4 '17 at 17:28
  • @Andrew -Is the \AtBeginEnvironment route somehow problematic? – Mico Dec 4 '17 at 18:19

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.