[Tex/LaTex] How to count the total number of sections within a chapter

counters

How can one count the total number of sections within each chapter?

I am trying to use the totcount package, but it returns the total number of sections of the last chapter, not total number of sections of the current chapter.

In the following MWE, the desired behaviour would be to report 3 sections for the first Chapter, and 1 section for the second and last chapter.

totcount reports only 1 section (the counter value for the last chapter).

\documentclass[12pt]{book}

\usepackage{totcount}
\regtotcounter{section}

\begin{document}
\chapter*{First Chapter}

The total number of sections in this chapter should be 3.

The totcount package reports: \total{section}

\section{First Section}
First text

\section{Second Section}
Second text

\section{Third Section}
Third text

\chapter*{Last Chapter}

The total number of sections in this chapter should be 1.

The totcount package reports: \total{section}

\section{First and only section}
Section text

\end{document}

How can one count the total number of sections within each chapter?

Note: totcount reports 0 sections if using \section*, see Sigur's comment.

Best Answer

Edit The look-ahead - version of knowing section numbers per chapter in advance is at the very end of this post. It requires two runs of compilation.

This question lead to a new package cntperchap which is available in its version 0.2 on CTAN since 2015/9/5

This uses the assoccnt package (whose author I accidentally know quite well ;-))

It associates a counter totalsections to the section counter -- each time the section counter is increased, the totalsections counter is stepped as well.

However, there is no automatic resetting for \chapter* usage. In this case, it can be done automatically by prepending some code to \chapter using \xpretocmd from xpatch package

Note The author of assoccnt should really incorporate this into his package ;-)

\documentclass[12pt]{book}
\usepackage{assoccnt}

\usepackage{xpatch}
\newcounter{totalsections}[chapter] % Does not work with `chapter*`

% Automatically provide for resetting of the section counter each time 
%`\chapter` or `\chapter*` is used -- in this setup this is requested.
\xpretocmd{\chapter}{\setcounter{totalsections}{0}}{}{}


\DeclareAssociatedCounters{section}{totalsections}

\begin{document}
\chapter*{First Chapter}

The total number of sections in this chapter should be 3.



\section{First Section}
First text

\section{Second Section}
Second text

\section{Third Section}
Third text

There \number\value{totalsections} sections in this chapter

\chapter*{Last Chapter}


\section{First and only section}
Section text

There \number\value{totalsections} sections in this chapter


\end{document}

Edit Some new version, which uses a per chapter count of sections (requires two runs to be successful).

Explanation: Each time a new chapter is used, the accumulated number of sections is written to external file, \jobname.seccnt, say foo.seccnt for short. This file is read again at the next latex compile run and the values are stored to a etoolbox list. The macro \GetTotalSectionCounter will advance through this list until it's at the right position and will then print out the number of sections in this chapter, even ahead. (The macro should be expandable, I think this is the case)

At the moment, it's necessary to manually remove the foo.seccnt file if there have been changes to number of chapters/sections.

I'll try to get around this drawback.

\documentclass{book}

\usepackage{ifthen}
\usepackage{assoccnt}

\usepackage{xpatch}

\usepackage{pgffor} % Only for quick usage of a lot of sections, demo only

\newwrite\seccountfile%

\newread\seccountinfile%

\listgadd{\seccountlist}{}% Initialize an empty list


\newcounter{currentchapter}
\newcounter{totalsections}
\newcounter{togglecounter}

\DeclareAssociatedCounters{section}{totalsections}


\newcommand{\getsectioncountnumbers}{%
  \setcounter{togglecounter}{0}%  
  \whiledo {\value{togglecounter} < 1}{%
    \read\seccountinfile to \gandalf%
    \ifeof\seccountinfile%
    \stepcounter{togglecounter}%
    \else%
    \listxadd{\seccountlist}{\gandalf}%
    \fi%
  }%
}


\xpretocmd{\chapter}{%
  \stepcounter{currentchapter}%
  \immediate\write\seccountfile{%
    \number\value{totalsections}%
  }%
  \setcounter{totalsections}{0}
}{}{}

\makeatletter
\newcounter{tempcount@a}
\newcommand{\@getsectiontotalcounter}[1]{%
  \setcounter{tempcount@a}{0}%
  \renewcommand*{\do}[1]{%
    \ifnumequal{\value{#1}}{\value{tempcount@a}}{%
      ##1\listbreak%
    }{%
      \stepcounter{tempcount@a}%
    }%  
  }%    
  \dolistloop{\seccountlist}%
}   


\newcommand{\GetSectionTotalCounter}[1][currentchapter]{%
  \ifdef{\seccountlist}{%
    \@getsectiontotalcounter{#1}%
    }{}%
}

\makeatother


\AtBeginDocument{%
  \IfFileExists{\jobname.seccnt}{%
    % Open for reading
    \immediate\openin\seccountinfile=\jobname.seccnt%
    \getsectioncountnumbers%
  }{%
    % Open for writing
    \immediate\openout\seccountfile=\jobname.seccnt%
  }%
}



\AtEndDocument{% 
  \immediate\write\seccountfile{%
    \number\value{totalsections}%
  }%
  \immediate\closeout\seccountfile%
}




\begin{document}

\chapter*{First}
This chapter will have \GetSectionTotalCounter sections
\section{First}
\section{Second}

\chapter*{Second}
This chapter will have \GetSectionTotalCounter sections
\section{First}
\section{Second}
\section{Third}
\section{Fourth}


% Now a really large chapter
\chapter*{Third}
This chapter will have \GetSectionTotalCounter sections

\foreach \x in {1,...,100} {%
\section{\x}
}

\end{document}

Edit This is the version without explicit deleting the foo.seccnt file

I used the addtocontents approach to let LaTeX write the section numbers to a separate file just as it is done with the toc related stuff. The foo.seccnt is then treated as a faked toc, read in before (and the values temporarily stored) rewritten in the run.

\documentclass{book}

\usepackage{ifthen}
\usepackage{assoccnt}
\usepackage{xpatch}
\usepackage{pgffor}

\listgadd{\seccountlist}{}% Initialize an empty list

\newcounter{currentchapter}
\newcounter{totalsections}
\newcounter{togglecounter}

\DeclareAssociatedCounters{section}{totalsections}


\makeatletter
\newcommand{\getsectioncountnumbers}{%
  \setcounter{togglecounter}{0}%  
  \whiledo {\value{togglecounter} < 1}{%
    \read\tf@seccnt to \seccountnumberfromfile%
    \ifeof\tf@seccnt
    \stepcounter{togglecounter}%
    \else%
    \listxadd{\seccountlist}{\seccountnumberfromfile}%
    \fi%
  }%
}


\xpretocmd{\chapter}{%
  \stepcounter{currentchapter}%
  \addtocontents{seccnt}{%
    \number\value{totalsections}%
  }%
  \setcounter{totalsections}{0}
}{}{}

\newcounter{tempcount@a}
\newcommand{\@getsectiontotalcounter}[1]{%
  \setcounter{tempcount@a}{0}%
  \renewcommand*{\do}[1]{%
    \ifnumequal{\value{#1}}{\value{tempcount@a}}{%
      ##1\listbreak%
    }{%
      \stepcounter{tempcount@a}%
    }%  
  }%    
  \dolistloop{\seccountlist}%
}   

\newcommand{\GetSectionTotalCounter}[1][currentchapter]{%
  \ifdef{\seccountlist}{%
    \@getsectiontotalcounter{#1}%
  }{}%
}

% This is a modified version from \@starttoc, being defined latex.ltx
\def\@startfaketoc#1{%
  \begingroup
  % Generate the file handle first
  \expandafter\newwrite\csname tf@#1\endcsname%
  \makeatletter
  % Read first before deleting it
  \ifcsdef{tf@#1}{%
    \IfFileExists{\jobname.#1}{%
    \immediate\openin\csname tf@#1\endcsname \jobname.#1\relax
    \getsectioncountnumbers%
    }{}
  }{%
    \typeout{No section count numbers so far}
  }%
  \if@filesw
  % Write only if not `\nofiles` is specified
  \immediate\openout \csname tf@#1\endcsname \jobname.#1\relax
  \fi
  \@nobreakfalse
  \endgroup%
}


\AtBeginDocument{%
  \@startfaketoc{seccnt}
}



\AtEndDocument{%
  % Write the last section count to the file
  \addtocontents{seccnt}{%
    \number\value{totalsections}%
  }%
}
\makeatother




\begin{document}
\tableofcontents

\chapter*{First}
This chapter will have \GetSectionTotalCounter sections
\section{First}
\section{Second}

\chapter*{Second}
This chapter will have \GetSectionTotalCounter sections
\section{First}
\section{Second}
\section{Third}
\section{Fourth}



% Now a really large chapter
\chapter*{Third}
This chapter will have \GetSectionTotalCounter sections

\foreach \x in {1,...,100} {%
\section{\x}
}

\chapter{Fourth}
This chapter will have \GetSectionTotalCounter sections

\section{A single section}


\end{document}

Edit The OP gsl noted some error in this code. I could track it down to the fact that \@startfaketoc tries to read in the external foo.seccnt file in the first run already. This fails of course, since there is no such file if it was deleted or the documentat is compiled for the very first time.