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.

LaTeX's low-level programming is poorly documented and the section on what is called control commands is even more so.

LaTeX provides the \@for macro. This works by repeatedly assigning list items to a temporary variable:

I want to define a list that will include all the greek math letters. The list is defined as follows:

\newcommand{\mathList}{\alpha,\beta,\gamma,
               \delta,\epsilon,\zeta,\theta}

To iterate over the list I have used the @for macro. For example the following explodes the list and removes the comma.

   \@for\i:=\mathList\do{%
      \ensuremath \i \space 
    }

How can I define a macro to be able to delete the nth element of the list? I have figured out appending to the list but have not posted it for brevity. I would prefer a TeX or LaTeX solution, although I would also be curious to see how it is done in LaTeX3, so all solutions are welcome.

Minimal example for convenience below:

\documentclass[11pt]{article}
\begin{document}
\makeatletter
\let\dotlessi\i
\newcommand*{\mathList}{\alpha,\beta,\gamma,
               \delta,\epsilon,\zeta,\theta, }
\@for\i:=\mathList\do{%
  \ensuremath \i \space 
 }
\let\i\dotlessi
\makeatother
\end{document}
share|improve this question
3  
Can we allow @ in tags please? –  Yiannis Lazarides Nov 21 '10 at 18:22
1  
Have you looked at etextools? tug.ctan.org/cgi-bin/ctanPackageInformation.py?id=etextools It has a lot of CSV manipulation stuff in it, so maybe you don't need to re-invent the wheel. :) –  Willie Wong Nov 21 '10 at 18:34
    
@Willie Thanks. I know of the package, but I am half-way reading through source2e trying to boost by understanding of TeX. Datatool can probably achieve it also. –  Yiannis Lazarides Nov 21 '10 at 18:43
    
Tangentially: some operations are more easily done on \@elt-lists, i.e. \@elt{\alpha}\@elt{\beta} etc., by defining \@elt appropriately and executing of \edefing the list. –  Ulrich Schwarz Nov 21 '10 at 21:57
1  
In ConTeXt, you can use \addtocommalist to add an element to a comma list (if it does not exist already), \removefromcommalist to remove an element, \appendtocommalist and \prependtocommalist to append an element (without checking if it is already there), \getfromcommalist to get the n-th element from a comma list, etc. If you are interested in a ConTeXt solution, I can post more details. –  Aditya Nov 21 '10 at 22:03
show 3 more comments

3 Answers 3

up vote 11 down vote accepted

Here is one way (deleting item number 3 from the list):

\count@=0
\toks@{}
\@for\i:=\mathList\do{%
  \advance\count@ 1
  \ifnum\count@=3 \else
    \edef\0{\the\toks@\expandafter\noexpand\i,}%
    \toks@\expandafter{\0}%
  \fi
 }%
\edef\mathList{\the\toks@}
share|improve this answer
    
Good answer. Are \count@ and \toks@ registers LaTeX creates for local use like this? Or do you have to declare them earlier? –  Matthew Leingang Nov 22 '10 at 10:38
    
And what is \0? –  Matthew Leingang Nov 22 '10 at 10:40
    
@Matthew: \count@ and \toks@ are temporary registers for local use. They originated in plain TeX and LaTeX includes them as well. (LaTeX also has a number of other temporary registers of various types.) For completeness, \toks@ is just \toks0 and \count@ is \count255 (\count0 is the page number). \0 is just a control symbol that is being defined. It's not anything special. –  TH. Nov 22 '10 at 11:36
    
Good answer. It needs a minor amendment though in order not to add an extra comma at the end. This can be removed by checking if the temp variable is empty before defining the `\0'. My macro for adding an item does not use token registers. –  Yiannis Lazarides Nov 22 '10 at 12:04
add comment

Here is a summary of different comma list manipulation commands in ConTeXt.

This is how I would do this in ConTeXt.

Define the list

\def\MathList{alpha,beta,gamma,delta,epsilon,zeta,theta}

ConTeXt does not remove spaces from each element of the list. This {alpha, beta} is different from {alpha,beta}.

Next define a macro to display a list element

\def\ShowListElement#1{\mathematics{\getvalue{#1}}\space}

To display the entire list:

\processcommacommand[\MathList]\ShowListElement

To add an element to the end of the list:

\addtocommalist {phi} \MathList
\processcommacommand[\MathList]\ShowListElement

To add an element to the beginning of the list:

\pretocommalist {kappa} \MathList
\processcommacommand[\MathList]\ShowListElement

The element is added only if does not exist already.

\addtocommalist {alpha} \MathList
\processcommacommand[\MathList]\ShowListElement

To delete an element from the list:

\removefromcommalist {gamma} \MathList
\processcommacommand[\MathList]\ShowListElement

To add an element to a list (without checks):

\appendtocommalist  {nu} \MathList
\prependtocommalist {nu} \MathList
\processcommacommand[\MathList]\ShowListElement

To substitute the value of an element:

\substituteincommalist {delta} {Delta} \MathList
\processcommacommand[\MathList]\ShowListElement

To get the size of a comma list

\getcommacommandsize [\MathList]
\commalistsize

Get indexed element from comma list

\getfromcommacommand [\MathList] [2]
\commalistelement

Replace an element from comma list

\def\newcommalistelement {iota}
\replaceincommalist \MathList {2}
\commalistelement \crlf
\processcommacommand[\MathList]\ShowListElement

To reverse a comma list. The result is stored in \reversedlist

\reversecommacommand\MathList
\processcommacommand[\reversedlist]\ShowListElement

Each command that uses commacommand also has a commalist variant that can be used if the list is not stored in a macro (for example, while processing key value lists).

There are a few other functions that are specific to numeric lists (sorting, compressing, expanding, etc).

share|improve this answer
add comment

In expl3, you would write

 \clist_remove_element:Nn \l_tmpa_clist {foo}

to remove foo from the comma-list variable \l_tmpa_clist. There is also a global \clist_gremove_element:Nn. The technique used is much the same as posted by Harald: the list is iterated over, and if the element is not matched then it is pushed onto a new clist.

Update: In the spirit of Aditya's summary of clist methods for ConTeXt, here's a few more expl3 examples (this covers the broad features but doesn't touch on everything). To initialise:

\clist_new:N \l_tmpa_clist
\clist_clear:N \l_tmpa_clist

To add data:

\clist_put_left:Nn \l_tmpa_clist {a}
\clist_put_right:Nn \l_tmpa_clist {b}

To iterate/map over:

\clist_map_inline:Nn \l_tmpa_clist { this is element: #1 \\ }
\clist_map_inline:nn {a,b,c} { this is element: #1 \\ }

Querying:

\clist_if_in:NnTF \l_tmpa_clist {a} {true} {false} 

Manipulating:

\clist_remove_duplicates:N \l_tmpa_clist
\clist_remove_element:Nn \l_tmpa_clist {c}

Of course, you don't have to follow the expl3 naming scheme for variables; in scratch code it's perfectly fine to write \foo instead of \l_tmpa_clist.

Comma-lists in expl3 generally do not contain empty elements, and spaces around elements are preserved (this is an arguable point that might change slightly in the future). They can contain anything except un-protected commas.

expl3 also provides a structure called a "sequence" that are used similarly to clists but are intended to be used when only internal functions are adding to/manipulating the data; comma-lists as a data structure are only really necessary when they inherit their data from document-level input. (The advantage to using sequences are slightly more generic processing and you can include commas in their elements.)

share|improve this answer
    
FWIW, the ConTeXt implementation of removing the element does not iteate over the list. See the definition of removefromcommalist in mult-aux.mkiv. –  Aditya Nov 22 '10 at 21:46
    
@Aditya there are two ways to remove an element. One is by referring to it by position say \remove{3}{\alist} (Harald's solution) or by name. The more common method is to refer to it by name \remove{\alpha}{\alist}'. In the latter since we can capture the beginning of the list up to the deletion in an argument #1,#2,#3, iteration is unecessary. One can also define variables on the fly to store the position in the list, which can solve the first case without iteration. I guess it all depends on the interface. If one would say use \additem{} to build a list no iteration is necessary. –  Yiannis Lazarides Nov 22 '10 at 22:43
    
@Yiannis: This is similar to how the corresponding macros are implemented in ConTeXt. And that is why I was surprised by Will's remark that "the list is iterated over, and if the element is not matched then it is pushed onto a new list" –  Aditya Nov 23 '10 at 16:06
    
@Aditya The iteration approach is more robust when your clist contains arbitrary material involving braces etc. Which is arguably not material fit for a clist, but anyway — \def\clist{aa,a{b}c,cc} \removefromcommalist{a{b}c}\clist fails. –  Will Robertson Nov 24 '10 at 2:25
    
thanks for the explanation and the updated answer –  Aditya Nov 24 '10 at 3:46
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.