Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Special formatting of a mathmode list

27 views
Skip to first unread message

Werner Grundlingh

unread,
May 20, 2011, 1:19:26 AM5/20/11
to
Hi all,

I'm interested in creating a macro that would parse and format/typeset a comma-separated list in math mode. For example,

This is my list: $P=\{\mathlist{a,b,c,d,e}\}$.

The output of the macro should process the list and output:

This is my list: $P=\{a$, $\!b$, $\!c$, $\!d$,~$\!e\}$.

In essense, the macro should do the following:
* Insert a ',' after all but the last element;
* Insert a ' ' after the ',' (in order to allow for logical line breaking in the list of items);
* Insert a '\!' to shorten the gap between list elements so as to distinguish the space between elements from the traditional '\ ' in regular text; and
* Use a '~' (non-breaking space) for the last space (in order to minimize possible orphaned or widowed words at the end of a paragraph).

My quick attempt at trying to code something like this (with an optional 'item separator' command) made use of the etoolbox package. However, I'm not sure whether there are better ways of doing it (there surely must be). Also, the macro seems to gobble up the separator, and I don't know how to fix that...

Thanks in advance for any help,
Werner

\documentclass{article}
\usepackage{etoolbox}%

\makeatletter
\newcommand{\mathlist}[2][noargument]{%
\xdef\lst@sep{,}% Default list separator is ','
\ifstrequal{#1}{noargument}{}{\xdef\lst@sep{#1}}%
% List (#2) is parsed completely the first time to count the number of items
\numdef\lst@total{0}% Initialize list count total to 0 (in case user supplies an empty list)
\renewcommand*{\do}[1]{\numdef\lst@total{1+\lst@total}}% Count number of items in list
\docsvlist{#2}% Parse list with above \do command/macro
% List (#2) is parsed a second time, formatting items sequentially
\ifnumless{\lst@total}{2}{#2}% If there are fewer than 2 items in list, just print the list
{% ...otherwise, process and print it item by item
\renewcommand*{\do}[1]{%
\numdef\lst@curitem{1+\lst@curitem}% Keep track of current item in list
\ifnumequal{\lst@curitem}{1}{% If we're at the first item, then...
##1 % Print '#1'
}{\ifnumequal{\lst@curitem}{\lst@total}{% ...else, if we're at the last item, then...
$\lst@sep\space~$\!##1 % Print ',~#1'
}{% ...else (item second,...,last), then...
$\lst@sep\space $\!##1 % Print ', #1'
}}%
}
\docsvlist{#2}% Parse list with above \do command/macro
}%
}%
\makeatother

\begin{document}

This is my list: $P=\{\mathlist{v_1,v_2,v_3,v_4,v_5}\}$

\end{document}

Enrico Gregorio

unread,
May 20, 2011, 4:21:55 AM5/20/11
to
Werner Grundlingh <wgrun...@gmail.com> wrote:

I wouldn't exit and reenter math mode, as one can define break points
in math formulas by introducing a penalty.

====
\usepackage{etoolbox}

\makeatletter
\newcommand{\mathlist}[1]{
\begingroup
% count the elements
\@tempcnta=\z@
\renewcommand*\do[1]{\advance\@tempcnta\@ne}
\docsvlist{#1}
\chardef\@listsize\@tempcnta
\@tempcnta=\@ne
\renewcommand*\do[1]{
\ifnum\@tempcnta<\@listsize
##1,\penalty\z@ \advance\@tempcnta\@ne
\else
\unpenalty##1
\fi}
\docsvlist{#1}
\endgroup
}
\makeatother
====

We do two passes over the list, one to count its elements, the
second one to typeset them. If the element is not the last, in the
second pass, it's followed by a comma and a zero penalty that allows
splitting the line there (use a larger value if you wish to
discourage breaks after commas); at the last element we destroy
the penalty inserted by the preceding element.

A test to show that the last element won't go to the next line alone
and that the spacing is the usual one in math lists.

====
\fboxsep=0pt \def\fparbox#1#2{\fbox{\parbox{#1}{#2}}}
This is my list: $P=\{\mathlist{a,b,c,d,e}\}$\par
\fparbox{4cm}{This is my list: $P=\{\mathlist{a,b,c,d,e}\}$}\par
\fparbox{4.2cm}{This is my list: $P=\{\mathlist{a,b,c,d,e}\}$}\par
\fparbox{4.4cm}{This is my list: $P=\{\mathlist{a,b,c,d,e}\}$}\par
\fparbox{4.6cm}{This is my list: $P=\{\mathlist{a,b,c,d,e}\}$}\par
\fparbox{4.8cm}{This is my list: $P=\{\mathlist{a,b,c,d,e}\}$}\par
\fparbox{5cm}{This is my list: $P=\{\mathlist{a,b,c,d,e}\}$}\par
An empty list: $P=\{\mathlist{}\}$\par
A one element list: $P=\{\mathlist{a}\}$\par
An implicit list: \def\xyz{a,b,c}$P=\{\mathlist\xyz\}$\par
====

Ciao
Enrico

GL

unread,
May 20, 2011, 4:50:49 AM5/20/11
to
Le 20/05/2011 07:19, Werner Grundlingh a écrit :
> Hi all,
>
> I'm interested in creating a macro that would parse and format/typeset a comma-separated list in math mode. For example,
>
> This is my list: $P=\{\mathlist{a,b,c,d,e}\}$.
>
> The output of the macro should process the list and output:
>
> This is my list: $P=\{a$, $\!b$, $\!c$, $\!d$,~$\!e\}$.
>
> In essense, the macro should do the following:
> * Insert a ',' after all but the last element;
> * Insert a ' ' after the ',' (in order to allow for logical line breaking in the list of items);
> * Insert a '\!' to shorten the gap between list elements so as to distinguish the space between elements from the traditional '\ ' in regular text; and
> * Use a '~' (non-breaking space) for the last space (in order to minimize possible orphaned or widowed words at the end of a paragraph).

If you relax the condition for the last item, there is something
shorter possible:

\documentclass{article}
\usepackage {nccstretch}

\begin{document}

\def\mathlist#1{\stretchwith{ \penalty0 }{#1}}

$P=\{\mathlist{a,b,c,d,e}\}$.


\end{document}\endinput

Enrico Gregorio

unread,
May 20, 2011, 5:30:07 AM5/20/11
to
GL <goua...@gmail.com> wrote:

> If you relax the condition for the last item, there is something
> shorter possible:
>
> \documentclass{article}
> \usepackage {nccstretch}
>
> \begin{document}
>
> \def\mathlist#1{\stretchwith{ \penalty0 }{#1}}
>
> $P=\{\mathlist{a,b,c,d,e}\}$.
>
>
> \end{document}\endinput

This assuming that the OP would accept that a comma goes alone in
the next line, of course. Most likely he won't.

Ciao
Enrico

GL

unread,
May 20, 2011, 5:44:43 AM5/20/11
to

Yes, \stretchwith is \@tfor not \@for... I noticed this after posting.
Anyway \stretchwith is a simple command that worth to be known ;-)

Thanks.
Florent.

Werner Grundlingh

unread,
May 20, 2011, 5:49:26 PM5/20/11
to
Thanks Enrico - this was exactly what I wanted. I've added back in (as in my original posting) an optional argument that would change the block used to separate list items. For example, allowing for
$P=\{\mathlist{v_1,v_2,v_3,v_4}\}$
that will be typeset with ',' separators, while
$P=\mathlist[;]{v_1,v_2,v_3,v_4}$ will be typeset with ';'.

Enrico Gregorio

unread,
May 20, 2011, 6:19:58 PM5/20/11
to
Werner Grundlingh <wgrun...@gmail.com> wrote:

Sure:

\makeatletter
\newcommand{\mathlist}[2][,]{


\begingroup
% count the elements
\@tempcnta=\z@
\renewcommand*\do[1]{\advance\@tempcnta\@ne}

\docsvlist{#2}


\chardef\@listsize\@tempcnta
\@tempcnta=\@ne
\renewcommand*\do[1]{
\ifnum\@tempcnta<\@listsize

##1#1\penalty\z@ \advance\@tempcnta\@ne
\else
\unpenalty\penalty\@M ##1
\fi}
\docsvlist{#2}
\endgroup
}
\makeatother

The optional argument can be anything, even an operation symbol
and the behavior will be almost the same, as TeX doesn't insert
the \binoppenalty or \relpenalty if there is already an explicit
penalty; with the original definition, the last element, in the
case an operation or relation symbol might be put to the next line
so I've added a \penalty10000 that is redundant with, say, a comma,
but not with a + or <.

Ciao
Enrico

0 new messages