1

As question Count and use the number of items in advance mentioned, I have the same demand, but mine is more advanced.

Here I have some enumerates, some of them begin with [resume] paramater, some of them have nested enumerate. I want to compute the number of the first level items of each enumerate. For example

enter image description here

I wrote codes below:

\documentclass{article}
\usepackage{enumitem}
\makeatletter
\newcounter{totalitems}
\newcounter{beginitems}
\newcounter{enditems}
\let\@numerate\enumerate

\def\enumerate{%
    \setcounter{beginitems}{\arabic{enumi}}
    \@numerate
}
\let\end@numerate\endenumerate
\def\endenumerate{
    \end@numerate%
    \setcounter{enditems}{\arabic{enumi}}
    \setcounter{totalitems}{\numexpr \c@enditems - \c@beginitems \relax}
}
\makeatother
\begin{document}
    \begin{enumerate}
        \item one
        \item two
    \end{enumerate}
    total = \thetotalitems, begin = \thebeginitems, end = \theenditems

    \begin{enumerate}[resume]
        \item three
        \begin{enumerate}
            \item a nested enumerate
        \end{enumerate}
    \end{enumerate}
    total = \thetotalitems, begin = \thebeginitems, end = \theenditems

    \begin{enumerate}
        \item one 
        \item two 
    \end{enumerate}
    total = \thetotalitems, begin = \thebeginitems, end = \theenditems
    
\end{document}

it produced:

enter image description here

As we can see there are some things goes wrong

  1. When there is nested enumerate, the beginitems counter is wrong
  2. When there is no [resume] paramater, the beginitems counter didn't been reset to 0.

Where should I change to reach my demand?

6
  • You need to postpone \setcounter{beginitems}{\arabic{enumi}} to after the enumerate environment was initiated, so essentially after \begin{enumerate} or \begin{enumerate}[resume]. Nov 10, 2021 at 7:38
  • yeah, I tried to put it after \@numerate, but this would lead an error: I can't add optional paramaters included [resume] of enumerate evironment,
    – Syvshc
    Nov 10, 2021 at 7:41
  • It might be easier to use the internal counters: enumi, enumii, enumiii and enumiv. You can also use \theenumi etc. Enumitem still uses them. It also adds a count for a series name: \csname enitdp@<name>\endcsname. Nov 10, 2021 at 17:22
  • REALY Thanks to @JohnKormylo !! I solve this question with your hint. I found the \enit@depth cotrol sequence to test which level is. Could you please write an answer? I'll give you the acceptance, or not I'll update my question and accept @Jasper's answer.Also a huge thanks for @JasperHabicht .
    – Syvshc
    Nov 11, 2021 at 1:27
  • I assumed this was just a test document to figure out how to get the counters. Go ahead and give it to Jasper. Nov 11, 2021 at 14:22

2 Answers 2

1

You need to postpone \setcounter{beginitems}{\arabic{enumi}} to after the enumerate environment was initiated, so essentially after \begin{enumerate} or \begin{enumerate}[resume] respectively. You need to take into account that \begin{environment} may have one optional argument.

I am not totally sure, but I think, using \LetLtxMacro instead of a plain \let and \renewcommand instead of \def is a bit more secure here:

\documentclass{article}
\usepackage{enumitem}

\makeatletter
\newcounter{totalitems}
\newcounter{beginitems}
\newcounter{enditems}

\usepackage{letltxmacro}
\LetLtxMacro{\@numerate}{\enumerate}
\LetLtxMacro{\end@numerate}{\endenumerate}

\renewcommand{\enumerate}[1][]{%
    \@numerate[#1]%
    \setcounter{beginitems}{\arabic{enumi}}
}
\renewcommand{\endenumerate}{
    \end@numerate%
    \setcounter{enditems}{\arabic{enumi}}
    \setcounter{totalitems}{\numexpr \c@enditems - \c@beginitems \relax}
}
\makeatother

\begin{document}

    \begin{enumerate}
        \item one
        \item two
    \end{enumerate}
    total = \thetotalitems, begin = \thebeginitems, end = \theenditems

    \begin{enumerate}[resume]
        \item three
        \begin{enumerate}
            \item a nested enumerate
        \end{enumerate}
    \end{enumerate}
    total = \thetotalitems, begin = \thebeginitems, end = \theenditems

    \begin{enumerate}
        \item one 
        \item two 
    \end{enumerate}
    total = \thetotalitems, begin = \thebeginitems, end = \theenditems
    
\end{document}

enter image description here

Now, you still may have the problem that the counters are affected every time, an enumerate environment starts, which may cause wrong results when enumerate environments are nested. I did not test this thouroughly.

4
  • 1
    Thanks for your answer! I was always thinking how to check if the optional paramater is resume or not. You saved me from this question. maybe I have to read some books to find what happens when nesting.
    – Syvshc
    Nov 10, 2021 at 8:11
  • 1
    Since the enumerate environment (if used with the enumitem) package only can take exactly one optional parameter (at least as far as I know), this will more or less cover all use cases. Nov 10, 2021 at 8:16
  • 1
    Ah, I know why counters after (a) went wrong. When we use the second level of enumerate, \begin of second level and \end of first level determined the value of beginitems and enditems. Both of them are 3, so we got a 0 of totalitems.
    – Syvshc
    Nov 10, 2021 at 8:28
  • I wrote an answer which reach my demand, thanks for your answer :)
    – Syvshc
    Nov 12, 2021 at 3:32
1

THANKS FOR @JohnKormylo and @JasperHabicht

method from @JasperHabicht

I found a control sequence \enit@depth which show the enumerate depth. So I can use \if to test if I'm in the first level, like this:

\renewcommand{\enumerate}[1][]{%
    \@numerate[#1]%
    \ifnum\enit@depth=\@ne
        \setcounter{beginitems}{\arabic{enumi}}
    \fi
}
\renewcommand{\endenumerate}{
    \ifnum\enit@depth=\@ne
        \setcounter{enditems}{\arabic{enumi}}
        \setcounter{totalitems}{\numexpr \c@enditems - \c@beginitems \relax}
    \fi
    \end@numerate%
}

If we do this, when we aren't in the first level, \setcounters won't work. The whole codes are:

\documentclass{article}
\usepackage{enumitem}

\makeatletter
\newcounter{totalitems}
\newcounter{beginitems}
\newcounter{enditems}

\usepackage{letltxmacro}
\LetLtxMacro{\@numerate}{\enumerate}
\LetLtxMacro{\end@numerate}{\endenumerate}

\renewcommand{\enumerate}[1][]{%
    \@numerate[#1]%
    \ifnum\enit@depth=\@ne
        \setcounter{beginitems}{\arabic{enumi}}
    \fi
}
\renewcommand{\endenumerate}{
    \ifnum\enit@depth=\@ne
        \setcounter{enditems}{\arabic{enumi}}
        \setcounter{totalitems}{\numexpr \c@enditems - \c@beginitems \relax}
    \fi
    \end@numerate%
}
\makeatother

\begin{document}

    \begin{enumerate}
        \item one
        \item two
    \end{enumerate}
    total = \thetotalitems, begin = \thebeginitems, end = \theenditems

    \begin{enumerate}[resume]
        \item three
        \begin{enumerate}
            \item a nested enumerate
        \end{enumerate}
    \end{enumerate}
    total = \thetotalitems, begin = \thebeginitems, end = \theenditems

    \begin{enumerate}
        \item one 
        \item two 
    \end{enumerate}
    total = \thetotalitems, begin = \thebeginitems, end = \theenditems
    
\end{document}

enter image description here

my new method

In this method, I renew the \item command, let the conter plus 1 when \item appears in the top level:

  1. first, we create a newif \ifenum to test if we are in the top level, we create a counter and save the macros:
\newif\ifenum
\newcounter{totalitems}

\usepackage{letltxmacro}
\LetLtxMacro{\@numerate}{\enumerate}
\LetLtxMacro{\end@numerate}{\endenumerate}
\LetLtxMacro{\it@m}{\item}
  1. use xparse to renew the \item command, when this \item is in the top level, step the counter totalitems. Also we can let it have some new features, like \item* for not count, \item[<paramater>] for a user-defined label as the previous definition but also count, \item*[paramater] for a user-defined label without count:
\DeclareDocumentCommand{\item}{ s o }{
    \IfNoValueTF{#2}{\it@m}{\it@m[#2]}  
    \ifenum
        \IfBooleanT{#1}{\addtocounter{totalitems}{-1}}%
        \stepcounter{totalitems}
    \fi
}
  1. Then we judge when should we true the \ifenum: after \begin{enumerate}, we test if we are in the top level, if true, set totalitems to 0, and set \enumtrue, if not, set \enumfalse; before \end{enumerate} act oppositely. It doesn't matter when nested list appears, because \ifenum always truns false when the second or deeper level begins.
\renewcommand{\enumerate}[1][]{%
    \@numerate[#1]
    \ifnum\enit@depth=\@ne
        \setcounter{totalitems}{0}
        \enumtrue
    \else
        \enumfalse
    \fi
}
\renewcommand{\endenumerate}{
    \ifnum\enit@depth=\@ne 
        \enumfalse
    \else
        \enumtrue
    \fi
    \end@numerate%
}

Now we can get the number of the top level items:

\documentclass{article}
\usepackage{enumitem}
\newif\ifenum
\makeatletter
\newcounter{totalitems}

\usepackage{letltxmacro}
\LetLtxMacro{\@numerate}{\enumerate}
\LetLtxMacro{\end@numerate}{\endenumerate}
\LetLtxMacro{\it@m}{\item}

\DeclareDocumentCommand{\item}{ s o }{
    \IfNoValueTF{#2}{\it@m}{\it@m[#2]}
    \ifenum
        \IfBooleanT{#1}{\addtocounter{totalitems}{-1}}%
        \stepcounter{totalitems}
    \fi
}

\renewcommand{\enumerate}[1][]{%
    \@numerate[#1]
    \ifnum\enit@depth=\@ne
        \setcounter{totalitems}{0}
        \enumtrue
    \else
        \enumfalse
    \fi
}
\renewcommand{\endenumerate}{
    \ifnum\enit@depth=\@ne 
        \enumfalse
    \else
        \enumtrue
    \fi
    \end@numerate%
}

\makeatother

\begin{document}

    \begin{enumerate}
        \item one
        \item two
    \end{enumerate}
    total = \thetotalitems

    \begin{enumerate}[resume]
        \item three
        \begin{enumerate}
            \item a nested enumerate
            \item* a star nest
        \end{enumerate}
        \item item after nested
    \end{enumerate}
    total = \thetotalitems

    \begin{enumerate}
        \item* a star version 
        \item[paramater] the only item which is counted
        \item*[paramater] a star version with paramater
    \end{enumerate}
    total = \thetotalitems
    
\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .