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 to modify the itemized environment (here called myitemized) so that it only shows the first N elements of the list. Basically I would like to be able to do something like

\documentclass{article}
\newcommand{\maxlist}{3}
\begin{document}
 \begin{myitemize}
  \item First item
  \item Second item
  \item Third item
  \item Fourth item
 \end{myitemize}
\end{document}

and get

  • First Item
  • Second Item
  • Third Item

where all items after \maxlist (3 in this example) are left out.

EDIT The answer by Niel de Beaudrap answers the stated question. For my application I would like to be able to wrap the truncating environment in another environment. Something like \newenvironment{wrapper}{\begin{truncitemize}}{\end{truncitemize}}.

share|improve this question
    
What is myitemize? Are the items saved in a macro? –  Marco Daniel Jun 11 '12 at 11:30
    
@MarcoDaniel I was using myitemize to represent a modified itemized environment. No, the items are not saved in a macro. –  StrongBad Jun 11 '12 at 11:46
    
For your additional requirement, you can do \makeatletter\newenvironment{wrapper{\begin{truncitemize}\bgroup\def\@currenvir‌​{wrapper}}\egroup\end{truncitemize}}\makeatother which, while slightly cludgy, should do the trick. Alternatively, you could adapt the \truncitemize macro to take an optional argument for the name of a wrapper environment, which would provide a slightly cleaner interface. If you're confident it won't get clobbered, even a very slight redefinition of the \begin macro to save the name of the current (i.e. wrapper) environment, for use by \truncitemize, would do. –  Niel de Beaudrap Jun 11 '12 at 17:28
add comment

2 Answers

up vote 14 down vote accepted

One can produce a solution by adapting some of the code from amsmath.sty. Don't worry about the details if they seem complicated, but here is some code that you can use, with some commentary.

Code to enable the ignoring of the remaining items in a list

We need some way of collecting everything that remains in the itemized list after a certain point, where the bullet points might also have environments in them. This strongly motivates that we use code very much similar to that used by the amsmath environments to collect the bodies of the align, gather, and other multi-line math environments.

Edit: as noted by egreg in the comments, most of this functionality is provided by the environ package, which we may include to simplify the code. However, we do still need a modified version of the main macro \collect@body, used in the amsmath environments, to control what is actually done with the list items that have been collected. We give it a different name so that it doesn't conflict with the existing macro, and modify it slightly. Specifically, the new macro doesn't accept (or do anything with) an argument, and rather than actually using the contents of the source which it has collected, it executes a macro to stand in for all of the remaining items in the list. (This macro can be modified, separately, to do whatever you like, including nothing at all.)

\usepackage{environ}% <--- for \collect@@body, etc.

\makeatletter

\def\truncatedlist@omit{%
  \edef\process@envbody{%
    \noexpand\let\noexpand\item\noexpand\orig@item
    \noexpand\omitlistitems \noexpand\end{\@currenvir}}%
  \@envbody\@emptytoks \def\begin@stack{b}%
  \begingroup
  \expandafter\let\csname\@currenvir\endcsname\collect@@body
  \edef\process@envbody{\expandafter\noexpand\csname\@currenvir\endcsname}%
  \process@envbody
}

Note in particular the first line, which redefines \item to be the value of some macro \orig@item. This is because, for your truncated list environment, we will be modifying the definition of \item, but might like to use the original meaning of \item when describing what to do instead of the omitted items.

Defining the new truncated list environment

Now we get to the point of the exercise. Define two counters:

\newcounter{trunclistnum}
\newcounter{trunclistlimit}
\setcounter{trunclistlimit}{3}% <--- or whatever limit you prefer

We also define what to do with the omitted items.

\def\omitlistitems{\item $\cdots$}
% or if you prefer, \def\omitlistitems{}

Finally, we define the list itself. The following code is basically a modification of the itemize environment as found in latex.ltx. It sets the count of the number of items to zero, and redefines \item to check whether the number of items exceeds the limit. If it does, it calls the macro which is used to omit the rest of the items; otherwise it calls a macro which contains the original behaviour of \item.

\let\endtruncitemize\enditemize
\def\truncitemize{%
  \ifnum \@itemdepth >\thr@@\@toodeep\else
    \c@trunclistnum=0\relax
    \let\orig@item\item
    \def\item{%
      \ifnum\c@trunclistnum<\c@trunclistlimit
        \let\@tempa\orig@item%
      \else
        \let\@tempa\truncatedlist@omit%
      \fi
      \advance\c@trunclistnum by 1%
      \@tempa}%
    \advance\@itemdepth\@ne
    \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}%
    \expandafter
    \list
      \csname\@itemitem\endcsname
      {\def\makelabel##1{\hss\llap{##1}}}%
  \fi}

\makeatother

Demonstration

Put all of that into the pre-amble of a document, and give the following a try:

\begin{document}

\subsection*{Result}
A truncated itemized list:
\begin{truncitemize}
\item First item
\item Second item
\item Third item
\item Fourth item
\item Yet further items  
\end{truncitemize}
A normal itemized list:
\begin{itemize}
\item First item
\item Second item
\item Third item
\item Fourth item
\item Yet further items  
\end{itemize}

\end{document}

output from sample code

share|improve this answer
    
Very nice answer! –  Alan Munn Jun 11 '12 at 14:24
    
The environ package makes available the amsmath machinery without having to reinvent it. –  egreg Jun 11 '12 at 14:29
    
@egreg: thanks for noting this, I've simplified my answer to make use of that. –  Niel de Beaudrap Jun 11 '12 at 14:37
    
I am working my way through this. What is the advantage of \edef\process@envbody{\expandafter\noexpand\csname\@currenvir\endcsname}% followed by \process@envbody over just \collect@@body. –  StrongBad Jun 11 '12 at 15:01
    
@DanielE.Shub: I see why you ask. To be frank, I do not know: it looks like those definitions are a lot of busy-work, and performing the replacement you suggest seems to work in the simple working example above. I operate under the assumption that there's a subtle reason for it. This might be a reasonable question on its own about the working of environ or amsmath. –  Niel de Beaudrap Jun 11 '12 at 16:22
add comment

We can let environ do the big work of loading the environment's content into \BODY. Then we redefine \item to advance a counter that we set to zero at the beginning of the itemize environment that we start; then the new \item checks whether the counter's value is above the threshold (\maxlist). In this case it lets \ignore@to@end gobble everything that remains (possibly printing an "omitted" item); otherwise it emits the usual \item that we keep in \old@item.

This can be even nested and the threshold can be changed locally with the optional argument.

\documentclass{article}
\usepackage{environ}

\makeatletter

\NewEnviron{myitemize}[1][\maxlist]{%
  \begin{itemize}
  \@tempcnta=\z@
  \def\item{\advance\@tempcnta\@ne\ifnum\@tempcnta>#1\relax
    \show@omitted@items
    \expandafter\ignore@to@end
      \else
    \expandafter\old@item
      \fi}%
  \BODY\final@sentinel
  \end{itemize}}

\long\def\ignore@to@end#1\final@sentinel{}%
\let\final@sentinel\@empty
\let\old@item\item

\newif\if@show@omitted
\newcommand{\showomitted}{\@show@omittedtrue}
\newcommand{\dontshowomitted}{\@show@omittedfalse}
\newcommand{\show@omitted@items}{\if@show@omitted\old@item\relax\dots\fi}
\makeatother

\newcommand{\maxlist}{3}

\begin{document}

\begin{myitemize}\showomitted
\item Yes
\item Yes
  \begin{myitemize}\dontshowomitted
\item Yes
\item Yes
\item Yes
\item No
\item No
\item No
\end{myitemize}
\item Yes
\item No
\item No
\item No
\end{myitemize}

separator

\begin{myitemize}[5]
\item Yes
\item Yes
\item Yes
\item No
\item No
\item No
\end{myitemize}

\end{document}
share|improve this answer
add comment

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.