Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I would like LaTeX to "know" how many items there are in a certain list. I want this number to be stored in a variable. In such a way I hope that this variable is sampled during the first compilation and available for the next compilations. Then I can refer to the number of items in my text before the list appears in the same text. How can I accomplish that? My minimum example does not work. Thanks in advance :)

\documentclass[10pt,a4paper,twosided]{article}
\usepackage{etoolbox}

\begin{document}

%The following list contains \NumberOfItems\ items

\begin{enumerate} 

\item item A
\item item B
\item item C

\end{enumerate}
\newcommand{\NumberOfItems}{\value{enumi}}

The previous list contains \NumberOfItems\ items


\end{document}
share|improve this question
    
I believe that your question addresses the same problem as this one: tex.stackexchange.com/questions/74595/… Please tell us if it is the case. If so, we could mark this as a duplicate. –  tohecz Feb 7 '13 at 11:40
    
@tohecz That question is specifically tailored for itemize. –  egreg Feb 7 '13 at 11:42
    
Please, add a link to the other related question and add also the solution to your minimal example. –  egreg Feb 8 '13 at 11:07
    
Are my changes what you asked for? –  Espen Donali Feb 8 '13 at 11:25
    
No, these aren't. However, you can exactly use \getrefnumber{firstlist} in place of your \NumberOfItems (requires the package refcount; firstlist is just the label assigned to the environment with enumeratecount) as I showed in my previous answer. –  egreg Feb 8 '13 at 11:27

4 Answers 4

up vote 7 down vote accepted

If you plan to use this only for first level lists and don't plan to use the enumitem package for personalizing the environment, using a \label in the last item is sufficient.

However a general solution that allows for rearrangement of items without bothering with the position of \label, is compatible also with enumitem and also works for nested list can be the following:

\documentclass[a4paper]{article}

\makeatletter
\newenvironment{enumeratecount}[1]
  {\def\thisenumeratecountlabel{#1}\enumerate}
  {\edef\@currentlabel{\number\value{\@enumctr}}%
   \label{\thisenumeratecountlabel}\endenumerate}
\makeatother

\begin{document}

The following list contains~\ref{firstlist} items, while
the nested list contains~\ref{innerlist}.

\begin{enumeratecount}{firstlist}
\item item A
\item item B
  \begin{enumeratecount}{innerlist}
  \item sub A
  \item sub B
  \end{enumeratecount}
\item item C
\end{enumeratecount}

The previous list contains \ref{firstlist} items, while the
inner list contains~\ref{innerlist}.

\end{document}

You just use \begin{enumeratecount}{<label>} for stating the label to be used (before or after the environment) for getting the number of items.

If you use enumitem you can even say

\begin{enumeratecount}{<label>}[<enumitem settings>]

so, for instance,

\begin{enumeratecount}{mylist}[label=\Alph*]

would work correctly (which wouldn't with the "simple method" outlined above and in Ulrike's answer).


The solution uses a couple of facts: a \label command refers to the current value of \@currentlabel, so before doing \endenumerate we define \@currentlabel to be the complete expansion of \value{\@enumctr}. The macro \@enumctr expands to enumi, enumii, enumiii or enumiv depending on the nesting level of the current enumerate environment; thus we're guaranteed to get the right number at all levels. Then we say \label{\thisenumeratecountlabel} that will set the label name to the original argument to enumeratecount. Locality of environments does the rest.


An extension

Suppose we want to say "the following list contains 1 item" or "the following list contains 3 items", adding the "s" conditionally.

This can be done with the help of the refcount package.

\usepackage{refcount}
\newcommand{\addphrase}[3]{% #1 = label, #2 = text if number >1, #3 = text if number =1
  \ifnum\getrefnumber{#1}>1
    #2%
  \else
    #3%
  \fi}

So the text above can be generated by

the following list contains \ref{firstlist}~\addphrase{firstlist}{items}{item}
share|improve this answer
    
Thanks a lot ! How can I use \ref{firstlist} in a if-then-else decision? Something like \ifnumcomp{\ref{firstlist}{>}{1}{do this}{else, do that} –  Espen Donali Feb 7 '13 at 16:56
    
@EspenDonali I've added some code. –  egreg Feb 7 '13 at 17:16
    
Thank again, but it is not exactly what i need. I need a new variable, made by \newcommand, with the value \ref{firstlist}, then I can use this variable in whatever commads from etoolbox. –  Espen Donali Feb 7 '13 at 17:20
    
@EspenDonali Please, make a new question, so that you can explain more clearly what you want, with some examples. –  egreg Feb 7 '13 at 17:44
    
Sure : ), and thanks to both of you giving me answers thus far! –  Espen Donali Feb 8 '13 at 9:46

In your example already \ref gives the correct output:

\documentclass[10pt,a4paper,twosided]{article}
\usepackage{etoolbox}


\begin{document}

The following list contains \ref{a} items

\begin{enumerate} 

\item item A
\item item B
\item\label{a} item C

\end{enumerate}
\end{document}
share|improve this answer
    
Not if the list is nested. –  egreg Feb 7 '13 at 11:48
3  
@egreg: I know. It also doesn't work if e.g. the numbering sheme is changed. That's why I wrote carefully "in the example ..." ;-). But I don't think that the question makes sense with nested lists. Would you write "The sub list of the second item hat 3 items?". –  Ulrike Fischer Feb 7 '13 at 11:56

Q: How can I count the number of items and store this number in a command by Q:\newcommand?

A: Add a counter to item

\let\olditem\item
\AtBeginEnvironment{enumerate}{
 \renewcommand{\item}{%
 \olditem%
 \stepcounter{mytempnumber}%
}}

As always one cannot redefine a macro recursive (that's why we need \let). I would like to recommend to use a counter for a number, not a macro.

Q: How can this be done, so that the value of this variable carries over to the next compilation where it can be available for "My conditional text" ?

A: Write it out! You can do this as value only, or as assignment:

\AtEndDocument{%
 \openoutputfile{\jobname.num}{number}
 \addtostream{number}{%%
 \noexpand\setcounter{mynumber}{\themytempnumber}} 
 \closeoutputstream{number}
}

We need to handle expansion carefully here, since everything is expanded when wrote to a file.

Here's the complete code:

\documentclass{article}
\usepackage{etoolbox}

\usepackage{newfile}

\newoutputstream{number}

\newcounter{mynumber}
\newcounter{mytempnumber}

\let\olditem\item
\AtBeginEnvironment{enumerate}{
 \renewcommand{\item}{%
 \olditem%
 \stepcounter{mytempnumber}%
}}

\AtEndDocument{%
\openoutputfile{\jobname.num}{number}
\addtostream{number}{%%
 \noexpand\setcounter{mynumber}{\themytempnumber}} 
\closeoutputstream{number}
}

\AtBeginDocument%
{%
\IfFileExists{\jobname.num}{\input{\jobname.num}}{\message{NO \jobname.num rerun!}}%
}

\begin{document}

\themynumber% use as normal counter

\begin{enumerate} 
\item Issue A
\item Issue B
\item Issue C
\item 
\end{enumerate}

\end{document}

I used etoolbox to hook into the enumerate environment and newfile to do the i/o stuff but more convenient. A interested user will notice, that the file <main file name>.num contents only one line of code: \setcounter{mynumber}{4}. So it's important to include the file before the usage of the counter.

share|improve this answer
    
Thanks for your thorough anwer! I will study it to see if I understand it, and then possibly implement it :) –  Espen Donali Feb 8 '13 at 13:59

I used the ifthen package instead of etoolbox as I am more familiar with the former; there is likely a similar construct in the latter. Create a new counter, say itemnum. Set the value of the counter at then end of your enumerate command. Then a little trickery: take 1 from the counter, then refstepcounter it, which adds one back and allows you to save its value in a label. The \ifthenelse command uses its value and compares it to 1.

This, of course, takes 2 runs to take effect as does any \label & \ref combination.

\documentclass[10pt,a4paper,twosided]{article}
\usepackage{ifthen}

\newcounter{itemnum}

\begin{document}

This report will addresses the following 
\ifthenelse{\ref{label:itemnum}=1}{issue}{issues}.


\begin{enumerate} 

\item Issue A
\item Issue B
\item Issue C
\setcounter{itemnum}{\value{enumi}}
\addtocounter{itemnum}{-1}
\refstepcounter{itemnum}\label{label:itemnum}

\end{enumerate}



\end{document}
share|improve this answer
    
Thanks! Your solution was simple and straightforward, and I will use it. –  Espen Donali Feb 8 '13 at 13:56

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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