tex: organize items in lists
warn: all source code here omit trailing %
due to blog template issues; if you
notice whitespace issues just add them back;
list is a basic data structure used in many languages; and it is common to have a pool of items arranged by lists; for example, all songs of a singer can be put in albums, all paragraphs of a book can be put in chapters, etc.;
the same is true for tex; sometimes we need to process items by lists; there does not seem to be builtin support for lists in plain tex where you can invoke a function on each item in a list; however, we can play with tex macros to do the same thing;
the trick is: we embed the function itself into the items, and do various jobs by changing the definition of the function, like this:
\def\AllItems{
\doitem{ZeroItem}{0}
\doitem{OneItem}{1}
\doitem{TwoItem}{2}
\doitem{ThreeItem}{3}
}
we can change the definition \doitem
to perform different actions on an item;
a full example
to make a full example, assume we have 4 items: zero
, one
, two
, three
,
whose values are 0
, 1
, 2
, 3
, respectively; and these 4 items are
organized into 2 lists:
-
list
foo
: containszero
andone
; -
list
bar
: containstwo
andthree
;
we want to define such a structure and be able to print items by lists;
here is the skeleton of the structure:
\def\AllItems{
\doitem{ZeroItem}{0}
\doitem{OneItem}{1}
\doitem{TwoItem}{2}
\doitem{ThreeItem}{3}
}
\def\FooList{
\doitem{ZeroItem}
\doitem{OneItem}
}
\def\BarList{
\doitem{TwoItem}
\doitem{ThreeItem}
}
\def\AllLists{
\dolist{FooList}
\dolist{BarList}
}
now the skeleton is there, and we want to add some flesh;
define the items
first of all, we need to actually define all the items; this is done by defining
\doitem
as below:
\def\doitem#1#2{\expandafter\def\csname #1\endcsname{#2}}
it is a simple macro that defines #1
to be #2
; for example:
\doitem{ZeroItem}{0}
\ZeroItem %% output: 0;
to define all items, just run the macro \AllItems
:
\AllItems
and now we can do:
\ZeroItem %% output: 0;
\OneItem %% output: 1;
\TwoItem %% output: 2;
\ThreeItem %% output: 3;
print items by lists
now all the items are defined, and we want to print them by lists; we alter the
definition of \doitem
from a definition to a print:
\def\doitem#1{\csname #1\endcsname}
we print an item by running its macro;
plus, we need a definition of \dolist
to print a list:
\def\dolist#1{\csname #1\endcsname}
ah, the same; we print a list by running its macro;
now we can do:
\AllLists %% output: 0123;
\BarList\FooList %% output: 2301;
and still we can print an item if we want:
\ZeroItem %% output: 0;
\OneItem %% output: 1;
\TwoItem %% output: 2;
\ThreeItem %% output: 3;
the full code
here is the full code you can run with tex
:
\def\AllItems{
\doitem{ZeroItem}{0}
\doitem{OneItem}{1}
\doitem{TwoItem}{2}
\doitem{ThreeItem}{3}
}
\def\FooList{
\doitem{ZeroItem}
\doitem{OneItem}
}
\def\BarList{
\doitem{TwoItem}
\doitem{ThreeItem}
}
\def\AllLists{
\dolist{FooList}
\dolist{BarList}
}
\def\doitem#1#2{\expandafter\def\csname #1\endcsname{#2}}
%%\doitem{ZeroItem}{0}
%%\ZeroItem %% output: 0;
%%\bye
\AllItems
%%\ZeroItem %% output: 0;
%%\OneItem %% output: 1;
%%\TwoItem %% output: 2;
%%\ThreeItem %% output: 3;
%%\bye
\def\doitem#1{\csname #1\endcsname}
\def\dolist#1{\csname #1\endcsname}
\AllLists %% output: 0123;
\BarList\FooList %% output: 2301;
%%\ZeroItem %% output: 0;
%%\OneItem %% output: 1;
%%\TwoItem %% output: 2;
%%\ThreeItem %% output: 3;
\bye
acknowledgement
this clever construction comes from the ucharclasses
package;
examples shown in this article have some modifications;