summaryrefslogtreecommitdiff
path: root/macros/generic/arrayjobx
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/generic/arrayjobx
Initial commit
Diffstat (limited to 'macros/generic/arrayjobx')
-rw-r--r--macros/generic/arrayjobx/README29
-rw-r--r--macros/generic/arrayjobx/arrayjob.pdfbin0 -> 463847 bytes
-rw-r--r--macros/generic/arrayjobx/arrayjob.sty188
-rw-r--r--macros/generic/arrayjobx/arrayjob.tex2097
-rw-r--r--macros/generic/arrayjobx/arrayjobx.pdfbin0 -> 464034 bytes
-rw-r--r--macros/generic/arrayjobx/arrayjobx.sty192
-rw-r--r--macros/generic/arrayjobx/arrayjobx.tex2096
7 files changed, 4602 insertions, 0 deletions
diff --git a/macros/generic/arrayjobx/README b/macros/generic/arrayjobx/README
new file mode 100644
index 0000000000..e8db2aec6f
--- /dev/null
+++ b/macros/generic/arrayjobx/README
@@ -0,0 +1,29 @@
+ +-----------------------------------------------------------+
+ | 'arrayjob'; 'arrayjobx' |
+ | Versions 1.03; 1.04 |
+ | May 3, 2000; May 3, 2010 |
+ | |
+ | Zhuhan Jiang (University of Western Sydney - Australia) |
+ | <zhuhan@scm.uws.edu.au> |
+ +-----------------------------------------------------------+
+
+
+The 'arrayjob(x)' package provides array data structures in (La)TeX, in the
+meaning of the classical procedural programming languages like Fortran, Ada or
+C, and macros to manipulate them. Arrays can be mono or bi-dimensional.
+
+This is useful for applications which require high level programming
+techniques, like algorithmic graphics programmed in the TeX language.
+
+The accompanying documentation files (arrayjob.tex, arrayjobx.tex ) were
+written by Denis Girou <Denis.Girou@idris.fr> and updated by Michael Sharpe
+(msharpe@ucsd.edu).
+
+Version 1.03 (arrayjob) is provided only for compatibility with old work that
+made explicit use of the \array macro. Version 1.04 (arrayjobx, modification
+suggested by Michael Sharpe) should be used for all new work---the only
+difference is that the macro known as \array in version 1.03 is known under
+the name \arrayx in version 1.04 in order to avoid conflict with the name
+\array as used in amsmath.
+
+This package is released under the terms of the LaTeX Project Public License.
diff --git a/macros/generic/arrayjobx/arrayjob.pdf b/macros/generic/arrayjobx/arrayjob.pdf
new file mode 100644
index 0000000000..a20bf9e175
--- /dev/null
+++ b/macros/generic/arrayjobx/arrayjob.pdf
Binary files differ
diff --git a/macros/generic/arrayjobx/arrayjob.sty b/macros/generic/arrayjobx/arrayjob.sty
new file mode 100644
index 0000000000..0712a49d11
--- /dev/null
+++ b/macros/generic/arrayjobx/arrayjob.sty
@@ -0,0 +1,188 @@
+% ARRAY STRUCTURE - arrayjob.sty - Version 1.03 - 05/03/00
+%
+% By Zhuhan Jiang (01/05/95), extracted from formlett.sty
+% (see CTAN/macros/generic/formlett.sty from line 344 to line 483)
+%
+% This program can be redistributed and/or modified under the terms
+% of the LaTeX Project Public License distributed from CTAN archives
+% in directory macros/latex/base/lppl.txt
+%
+% * 01/05/95 - Version 1.00
+% + Original version
+% * 12/21/99 - Version 1.01
+% + Spurious blanks removed in \read@array and \get@max@count
+% (reported by Antonio Leitao <aml@gia.ist.utl.pt>
+% and Denis Girou <Denis.Girou@idris.fr>)
+% * 04/05/00 - Version 1.02
+% + Add the \ifexpandarrayelement macro to allow to evaluate
+% or not the content to put as an element of the array
+% (from Denis Girou <Denis.Girou@idris.fr>)
+% + Put this package under the terms of the LaTeX Project
+% Public License
+% * 05/03/00 - Version 1.03
+% + Add a \ProvidesPackage macro when LaTeX is used
+% (according to the example given by Bernd Raichle
+% <raichle@Informatik.Uni-Stuttgart.DE>)
+%
+%
+% \newarray\ARRAYNAME
+% \delarray\ARRAYNAME
+%
+% \ARRAYNAME(A1,..,An)={T}
+% \readarray{ARRAYNAME}{ B1 & B2 & ... & Bm }
+% \dataheight
+%
+% \data(A1,...,An)=\data( A1 + (A2-1)*\dataheight +
+% ... + (An-1)*\dataheight^{n-1} )
+% if \normalindextrue
+% =\data( An + (An-1 -1)*\dataheight +
+% ... + (A1-1)*\dataheight^{n-1} )
+% if \normalindexfalse
+%
+% \checkARRAYNAME(A1,..,An)
+% \ifemptydata valid when \checkARRAYNAME is just executed
+% \cachedata: keeps the data of \ARRAYNAME(m)
+% when \checkARRAYNAME(m) is executed
+%
+% OTHERS:
+% save to array: \array{n}(m)={T}
+% get from array: \array{n}(m)
+% clear element: \clrarray{n}(m)
+% test element: \testarray{n}(m)
+% macro save to \temp@macro
+%
+%
+% e.g.
+%
+% \newarray\Table
+% \readarray{Table}{one&two& \unknownmacro && &six}
+% \Table(7)={seven}
+% \dataheight=0 % or 1 or < 0
+% \Table(7) = \Table(2,6,1) % 7=1+(2-1)+(6-1)+(1-1)
+% \normalindexfalse
+% \dataheight=3
+% \Table(7) = \Table(1,7) = \Table(3,1)
+% \normalindextrue
+% \Table(7) = \Table(7,1) = \Table(1,3)
+%
+% \checkTable(4) \ifemptydata (4)=empty \fi
+% \checkTable(5) \ifemptydata\else (5)=nonempty \fi
+% \ifx\cachedata\space ={\tt <space>}\fi
+% \checkTable(1000) \ifemptydata (1000)=empty \fi
+%
+% \delarray\Table
+%
+%
+\begingroup\expandafter\expandafter\expandafter\endgroup
+\expandafter\ifx\csname ProvidesPackage\endcsname\relax%
+\else
+ \ProvidesPackage{arrayjob}[2000/05/03 v1.03 Array management]
+\fi
+%
+\xdef\EntryArrayJob{\the\catcode`\@}\catcode`\@=11\relax
+\newif\ifemptydata \newcount\dataheight
+\newif\ifnormalindex \normalindexfalse
+%
+\newcount\array@width \newcount\index@count \newcount\index@total
+\newif\ifone@VEC \newif\if@rev@index
+\newtoks\temp@toks \newcount\temp@count
+\newcount\temp@@count \newcount\temp@@@count
+%
+\newif\ifexpandarrayelement
+%
+\long\def\assign@VEC#1(#2)=#3{\temp@count=#2 \relax
+\get@max@count{total@#1}\temp@count
+\ifexpandarrayelement
+ \expandafter\xdef\csname#1#2\string~\endcsname{#3}%
+\else
+ \expandafter\gdef\csname#1#2\string~\endcsname{#3}%
+\fi}
+\def\get@VEC#1(#2){\csname#1#2\string~\endcsname}
+\def\clrarray#1(#2){%
+ \global\expandafter\let\csname#1#2\string~\endcsname=\undefined@}
+%
+\def\testarray#1(#2){%
+ \expandafter\let\expandafter\temp@macro\csname#1#2\string~\endcsname
+ \ifx\temp@macro\relax \def\temp@macro{}\fi}%
+%
+\def\array#1(#2){\def\check@VEC{%
+ \ifx=\next@VEC \def\full@VEC####1{\assign@VEC#1(#2)####1}%
+ \else \def\full@VEC{\get@VEC#1(#2)}\fi \full@VEC}%check@VEC
+\futurelet\next@VEC\check@VEC}
+%
+\def\get@index(#1)#2\safty@mark{\one@VEC#2,\safty@mark
+ \def\next@@VEC{#1}\ifx\next@@VEC\empty\def\next@@VEC{\array@width}\fi
+ \if@rev@index
+ {\temp@count=1 \advance\index@count1 \relax
+ \ifnum\index@count<\index@total
+ \loop \multiply\temp@count \next@@VEC
+ \advance\index@count-1 \relax
+ \ifnum\index@count>0 \repeat
+ \fi \global\temp@@count\temp@count }%
+ \else \multiply\temp@@count \next@@VEC \fi
+ \ifnum\temp@@count=0 \temp@@count=1 \relax \fi
+ \advance\temp@count-1 \ifnum\temp@count<0 \temp@count=0 \fi
+ \multiply\temp@count \temp@@count
+ \advance\temp@@@count by \temp@count \advance\index@count1
+ \ifone@VEC
+ \def\next@@VEC{\index@total=\index@count \advance\temp@@@count1 }%
+ \else \one@VEC#2\safty@mark \edef\next@@VEC{\noexpand\get@index(#1)%
+ \the\temp@toks\noexpand\safty@mark}%
+ \fi \next@@VEC}%
+%
+\def\one@VEC#1,#2\safty@mark{\def\temp@macro{#2}\temp@toks={#2}%
+ \ifx\temp@macro\empty \one@VECtrue \else \one@VECfalse \fi
+ \temp@count=#1 \relax }%
+%
+\def\get@all@index(#1)#2\safty@mark{%
+ \temp@@@count=0 \temp@@count=0 \index@count=0 \@rev@indexfalse
+ \get@index(#1)#2\safty@mark
+ \ifnormalindex\else
+ \temp@@@count=0 \temp@@count=0 \index@count=0 \@rev@indextrue
+ \get@index(#1)#2\safty@mark \fi }%
+%
+\def\read@array[#1]#2#3{\temp@count=1
+ \def\one@item##1#1##2\safty@mark{\def\temp@macro{##2}\temp@toks={##2}%
+ \ifx\temp@macro\empty\else
+ \def\temp@macro{\one@item##2\safty@mark}\fi
+ {\temp@toks={##1}\def\temp@@macro{\array{#2}(\the\temp@count)=}%
+ \expandafter\temp@@macro\expandafter{\the\temp@toks}}%
+ \expandafter\edef\csname total@#2\endcsname{\the\temp@count}%
+ \advance\temp@count1\temp@macro}%
+ \one@item#3#1\safty@mark}%
+%
+\def\strip@esc#1{\temp@count=\escapechar \escapechar=-1 %
+ \temp@toks=\expandafter{\string#1}\escapechar\temp@count}
+\def\get@max@count#1#2{\edef\temp@macro{\csname #1\endcsname}%
+ \ifnum\temp@macro<#2\expandafter\xdef\csname #1\endcsname{\the#2}\fi}%
+%
+\def\newarray#1{\strip@esc{#1}%
+ \expandafter\gdef\csname total@\the\temp@toks\endcsname{0}%
+ \expandafter\edef\csname\the\temp@toks\endcsname(##1)%
+ {\noexpand\get@all@index(\noexpand\dataheight)##1\noexpand\safty@mark
+% \noexpand\get@max@count{total@\the\temp@toks}\noexpand\temp@@@count
+ \noexpand\array{\the\temp@toks}(\noexpand\the\noexpand\temp@@@count)}%
+ \expandafter\edef\csname check\the\temp@toks\endcsname(##1)%
+ {\noexpand\get@all@index(\noexpand\dataheight)##1\noexpand\safty@mark
+ \noexpand\testarray{\the\temp@toks}(\noexpand\the
+ \noexpand\temp@@@count)\noexpand\let\noexpand\cachedata
+ \noexpand\temp@macro\noexpand\ifx\noexpand\temp@macro\noexpand\empty
+ \noexpand\emptydatatrue\noexpand\else\noexpand\emptydatafalse
+ \noexpand\fi}}%
+%
+\def\delarray#1{\strip@esc{#1}% delete array globally
+ \temp@count=0 \temp@@count=\csname total@\the\temp@toks\endcsname
+ \loop \expandafter\global\expandafter\let
+ \csname\the\temp@toks\string~\endcsname\undefined@
+ \advance\temp@count1 %
+ \ifnum\temp@count<\temp@@count \repeat % global loop for less memory
+ \global\expandafter\let\csname total@\the\temp@toks\endcsname\undefined@
+ \global\expandafter\let\csname \the\temp@toks\endcsname\undefined@
+ \global\expandafter\let\csname check\the\temp@toks\endcsname\undefined@ }%
+%
+\def\readarray#1#2{\read@array[&]{#1}{#2}}%
+%
+\catcode`\@=\EntryArrayJob\relax
+\endinput
+%
+% END OF MACROS
diff --git a/macros/generic/arrayjobx/arrayjob.tex b/macros/generic/arrayjobx/arrayjob.tex
new file mode 100644
index 0000000000..899cfe39e7
--- /dev/null
+++ b/macros/generic/arrayjobx/arrayjob.tex
@@ -0,0 +1,2097 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -*- Mode: Latex -*- %%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% arrayjob.doc --- Documentation of the `arrayjob' package from Zhuhan Jiang
+%%
+%% Author : Denis GIROU (CNRS/IDRIS - France) <Denis.Girou@idris.fr>
+%% Created the : Fri Jan 7 21:13:20 2000
+%% Last mod. by : Denis GIROU (CNRS/IDRIS - France) <Denis.Girou@idris.fr>
+%% Last mod. the : Wed May 31 20:10:39 2000
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\documentclass{article}
+
+\usepackage{arrayjob} % Arrays management
+\usepackage{fancyvrb} % Fancy verbatims
+\usepackage[width=18cm]{geometry} % Page layout
+\usepackage{graphics} % Graphics LaTeX standard package
+\usepackage{ifthen} % Convenient conditionals in LaTeX
+\usepackage{mflogo} % For the MetaFont and MetaPost logos
+\usepackage{multido} % General loop macro
+\usepackage{url} % URLs convenient typesetting
+\usepackage{trace}
+
+% For PSTricks examples
+\newif\ifpstricks
+\IfFileExists{pstricks.sty}{%
+\pstrickstrue
+%\usepackage{pstcol} % PSTricks package with `color' interface
+\usepackage{pst-node} % PSTricks nodes package
+\usepackage{pst-plot} % PSTricks plots package
+\usepackage{pst-grad} % PSTricks gradients package
+%\usepackage{pst-key} % PSTricks interface to the `keyval' package
+}{%
+\usepackage{color}
+} % Color LaTeX standard package
+
+% Definition of new colors
+\definecolor{Khaki} {rgb}{0.94,0.90,0.55}
+\definecolor{LemonChiffon}{rgb}{1.,0.98,0.8}
+
+% A unique string for TeX and LaTeX
+\newcommand{\AllTeX}{%
+{\rm(L\kern-.36em\raise.3ex\hbox{\sc a}\kern-.15em)%
+T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}}
+
+% Package names
+\newcommand{\AlDraTeXPackage}{\textsf{(Al)Dra\TeX}}
+\newcommand{\ArrayJobPackage}{`\textsf{arrayjob}'}
+\newcommand{\FormLettPackage}{`\textsf{formlett}'}
+\newcommand{\IfThenPackage}{`\textsf{ifthen}'}
+\newcommand{\MetaFontPackage}{\MF}
+\newcommand{\MetaPostPackage}{\MP}
+\newcommand{\MultiDoPackage}{`\textsf{multido}'}
+\newcommand{\PSTricksPackage}{\textsf{PSTricks}}
+\newcommand{\RepeatPackage}{`\textsf{repeat}'}
+
+% Aligned labels in a description environment
+\newenvironment{Description}[1]{%
+\begin{list}{nothing}{\setlength{\leftmargin}{#1}
+\setlength{\labelwidth}{\leftmargin}\setlength{\labelsep}{1mm}}}
+{\end{list}}
+
+% If PSTricks is not available
+\newcommand{\PSTricksExampleNotShown}{%
+\vspace{2mm}
+\centerline{\fbox{\textbf{Example not shown here because PSTricks is not
+ available on this platform.}}}}
+
+% Character to define verbatim strings, with escape characters /?; (from `fancyvrb')
+\DefineShortVerb[commandchars=/?;]{\!}
+
+\VerbatimFootnotes % Allow verbatim material in footnotes (from `fancyvrb')
+
+% Some advices from Rolf Niepraschk
+\newcommand{\BS}{\texttt{\symbol{`\\}}}
+\newcommand{\Macro}[1]{\texttt{\BS#1}}
+\newcommand{\Variable}[1]{\textnormal{\textit{\(\langle\)#1\,\(\rangle\)}}}
+\newcommand{\Parameter}[1]{\texttt{\symbol{`\{}#1\symbol{`\}}}}
+
+% To format TeX macro strings
+\newcommand{\FormatTeXMacro}[1]{\Macro{#1}\hfill :}
+
+\makeatletter
+
+% Example environments
+% (do not use in them the /?; characters, that we will be used as escape characters!)
+
+% For highlighting some verbatim sequences (array names, macro names and comments)
+\def\HLReverse#1{{%
+\setlength{\fboxsep}{1pt}%
+\colorbox{black}{\textcolor{white}{\textbf{#1}}}}}
+\def\HLMacro#1{\BS{}def\HLMacro@i#1\@nil}
+\def\HLMacro@i#1def#2\@nil{{%
+\setlength{\fboxsep}{1pt}%
+\colorbox{black}{\textcolor{white}{\textbf{#2}}}}}
+\def\HLComment#1{\textit{#1}}
+
+\def\Example{\FV@Environment{}{Example}}
+\def\endExample{%
+\end{VerbatimOut}
+\Below@Example{\input{\jobname.tmp}}
+\endgroup}
+
+\def\CenterExample{\FV@Environment{}{Example}}
+\def\endCenterExample{%
+\end{VerbatimOut}%
+\begin{center}
+\Below@Example{\input{\jobname.tmp}}
+\end{center}
+\endgroup}
+
+\def\SideBySideExample{\FV@Environment{}{Example}}
+\def\endSideBySideExample{%
+\end{VerbatimOut}%
+\SideBySide@Example{\input{\jobname.tmp}}
+\endgroup}
+
+\def\FVB@Example{%
+\begingroup
+\FV@UseKeyValues
+\parindent=0pt
+\multiply\topsep by 2
+\VerbatimEnvironment
+\begin{VerbatimOut}[codes={\catcode`\Z=12}]{\jobname.tmp}}
+
+\def\Below@Example#1{%
+\VerbatimInput[gobble=0,commentchar=Z,commandchars=/?;,numbersep=3pt,
+ frame=single,numbers=left]%
+ {\jobname.tmp}
+\catcode`\Z=9\relax%
+% We suppress the effect of the highlighting macros
+\catcode`/=0\relax%
+\catcode`?=1\relax%
+\catcode`;=2\relax%
+\def\HLReverse##1{##1}%
+\def\HLMacro##1{##1}%
+\def\HLComment##1{##1}%
+#1\par}
+
+\def\SideBySide@Example#1{%
+\@tempdimb=\FV@XRightMargin
+\advance\@tempdimb -5mm
+\begin{minipage}[c]{\@tempdimb}
+ \fvset{xrightmargin=0pt}
+ \catcode`\Z=9\relax%
+ % We suppress the effect of the highlighting macros
+ \catcode`/=0\relax%
+ \catcode`?=1\relax%
+ \catcode`;=2\relax%
+ \def\HLReverse##1{##1}%
+ \def\HLMacro##1{##1}%
+ \def\HLComment##1{##1}%
+ #1
+\end{minipage}%
+\@tempdimb=\textwidth
+\advance\@tempdimb -\FV@XRightMargin
+\advance\@tempdimb 5mm
+\begin{minipage}[c]{\@tempdimb}
+ \VerbatimInput[gobble=0,commentchar=Z,commandchars=/?;,
+ numbersep=3pt,frame=single,numbers=left,
+ xleftmargin=5mm,xrightmargin=0pt]{\jobname.tmp}
+\end{minipage}}
+
+\makeatother
+
+% Source codes must be indented by 2 spaces
+\fvset{gobble=2,frame=single,numbers=left,numbersep=1mm}
+
+\begin{document}
+
+\title{The \ArrayJobPackage{} package\\Management of arrays in \AllTeX}
+\author{Zhuhan Jiang\\School of Computing and Mathematics\\
+ University of Western Sydney\\Sydney\\Australia\\
+ {\footnotesize email: zhuhan@scm.uws.edu.au}\\[5mm]
+ {\footnotesize (Documentation: Denis Girou%
+ \footnote{All errors and misunderstandings are mine.}
+ \hspace{1mm}(CNRS/IDRIS -- France) --
+ Denis.Girou@idris.fr)}}
+\date{Version 1.03\\May 3, 2000\\
+ {\small Documentation revised May 31, 2000, edited lightly May 3, 2010 by Michael Sharpe}}
+
+\maketitle
+
+\begin{abstract}
+ This package provides array data structures in \AllTeX, in the meaning of
+the classical procedural programming languages like Fortran, Ada or C, and
+macros to manipulate them. Arrays can be mono or bi-dimensional.
+
+ This is useful for applications which require high level programming
+techniques, like algorithmic graphics programmed in \TeX. This version conflicts with some macros in the {\tt amsmath} package. Version 1.04 resolves those issues. It should be used for all new work.
+\end{abstract}
+
+\tableofcontents
+
+\section{Introduction}
+
+ One of the big advantages of the \AllTeX{} system over common interactive
+software for text processing is that it offer, also, a programming language,
+which give, to people who have some knowledge in the algorithmic and
+programming fields, an exceptional flexibility and power.
+
+ Nevertheless, \TeX{} is a rather specific programming language, based on
+macro expansion, which implements a lot of unusual constructs but lacks some that are very familiar in the classical procedural languages, as
+\emph{arrays} to store and retrieve arbitrary pieces of data, stored in a
+structured way. The main reason why they were not integrated in \TeX{} was
+perhaps that arrays did not seem very useful in a language focussed on text processing (but
+\MetaFontPackage{}, for instance, does has them). Nevertheless, one of the few
+applications where this is straightforward to use them is to program a mailing
+system, where nearly the same information is to be formatted several times,
+depending of values which can be simply retrieved from an array of data. This
+was the goal of the \FormLettPackage{} package \cite{FORMLETT}, written in
+1993-1995 by Zhuhan Jiang for dealing with mass letters, invoices and similar
+tasks of some duplicative nature. It implemented a small but powerful set of
+macros to manage arrays, which have been extracted to form the present
+\ArrayJobPackage{} package. The arrays can be mono or bi-dimensional%
+\footnote{You can use more than two dimensions, but not in the meaning of the
+classical programming languages (see page \pageref{par:DataHeight})}
+and they are dynamically allocated (so we do not have to declare their
+dimension statically.)%
+\footnote{Stephan von Bechtolsheim \cite[Volume \textsc{III}, paragraph 20.3,
+page 136]{SVB93} also demonstrated such macros for array management in the
+third volume of his huge book, but it was limited to mono-dimensional
+arrays.}.
+
+ Array structures are, at the opposite of text management, often very useful
+in graphic programming. This is why the \AlDraTeXPackage{} package from Eitan
+Gurari \cite{ALDRATEX} (see also \cite{Gur94}) integrate such functionality
+(but which is bundled inside this package and could not be extracted easily
+from it), and this is also the case for the \MetaPostPackage{} package
+\cite{METAPOST} (but this one do not use \TeX{} as programming language)%
+\footnote{Another required feature, used in conjunction with the managements
+of arrays, is a generic loop mechanism. \TeX{} offer the \Macro{loop} macro
+and \LaTeX{} the \Macro{whiledo} macro of the \IfThenPackage{} package (and
+also the internal \Macro{@for}, \Macro{@whilenum}, etc. macros), but a more
+high-level structure is to be preferred, as the ones defined too in the
+\AlDraTeXPackage{} or \MetaPostPackage{} packages. We will use in our examples
+the \MultiDoPackage{} package \cite{MULTIDO}, also written by Timothy van
+Zandt, but others are available, like the \RepeatPackage{} package written by
+Victor Eijkhout \cite{REPEAT}.}. This fact explain why most of our examples in
+this documentation will concern the area of \emph{graphic programming} (here
+using the \PSTricksPackage{} package from Timothy van Zandt \cite{PSTRICKS}).
+
+\section{Command reference}
+
+\begin{Description}{4cm}
+ \item[\FormatTeXMacro{newarray}] Define a new array.
+
+ Syntax: !\newarray/Macro?/Variable?ArrayName;;!
+
+ Example: !\newarray\Values!
+
+ \item[\FormatTeXMacro{delarray}] Delete an array.
+
+ Syntax: !\delarray/Macro?/Variable?ArrayName;;!
+
+ Example: !\delarray\Values!
+
+ Remarks:
+ \begin{enumerate}
+ \item obviously, elements of a deleted array could not be accessed
+ later,
+ \item take care that the elements of a deleted array are not
+ themselves deleted.\newline
+ So, \verb+\delarray\Data \newarray\Data \Data(I)+ can produce
+ strange behavior. Just avoid reusing deleted arrays.
+ \end{enumerate}
+
+ \item[\FormatTeXMacro{ArrayName}] Store or get the content of the array
+ element specified by the index/indices. In the last case, the content is
+ inserted at the current point.
+
+ Syntax: !/Macro?/Variable?ArrayName;;(I)=/Parameter?/Variable?Content;;! or more
+ generally\newline
+ \hspace*{1.3cm}!/Macro?/Variable?ArrayName;;(I1,...,In)=/Parameter?/Variable?Content;;!
+ to store a value
+
+ \hspace{1.3cm}!/Macro?/Variable?ArrayName;;(I)! or more generally
+ !/Macro?/Variable?ArrayName;;(I1,...,In)! to retrieve a value
+
+ Examples: !\Data(6)={Paul Adams}!
+
+ \hspace{1.75cm}!\Values(19)!
+
+ \item[\FormatTeXMacro{readarray}] Store consecutive values in an array,
+ starting from the indice one.
+
+ Syntax: !\readarray/Parameter?/Variable?ArrayName;;=/Parameter?/Variable?Content1;&...&/Variable?ContentM;;!
+
+ Example: !\readarray{Actors}{Louise Brooks&Marlene Dietrich&Clark Gable}!
+
+ Remarks:
+ \begin{enumerate}
+ \item the values must be separated by the \textbf{\&} character,
+ \item take care that the trailing spaces are significant, so the
+ previous definition is different from the following one:
+
+ !\readarray{Actors}{Louise Brooks & Marlene Dietrich & Clark Gable}!
+ \item you can use \AllTeX{} macros inside the values.
+ \end{enumerate}
+\end{Description}
+
+\begin{SideBySideExample}[xrightmargin=6cm]
+ \newarray\Values
+ \readarray{/HLReverse?Values;}{A&B&C&D}
+ \verb+\Values(3)+ = `\Values(3)'
+ \newarray\Actors
+ \readarray{/HLReverse?Actors;}{Louise Brooks&Marlene Dietrich&Clark Gable}
+ Z\par
+ \verb+\Actors(2)+ = `\Actors(2)'
+ \readarray{/HLReverse?Actors;}{%
+ Louise Brooks & Marlene Dietrich & Clark Gable}
+ Z\par
+ \verb+\Actors(2)+ = `\Actors(2)'
+ \Actors(4)={\textit{\underline{Ida Lupino}}}
+ Z\par
+ \verb+\Actors(4)+ = `\Actors(4)'
+\end{SideBySideExample}
+
+\vspace{3mm}
+\noindent If you really need to trim the unnecessary left and right spaces, you must
+apply a special action, like this one:
+
+\begin{Example}
+ \def\BS{\texttt{\symbol{`\\}}}
+
+ \newarray\Strings
+ \readarray{/HLReverse?Strings;}{a& b&c c & d dd ddd }
+
+ \multido{\iString=1+1}{4}{%
+ \checkStrings(\iString)%
+ \BS\texttt{Strings(\iString)}=`\cachedata'\qquad}
+
+ \makeatletter
+
+ % /HLComment?A \TrimSpaces macro adapted from Michael J. Downes <epsmjd@ams.org>;
+ % /HLComment?(posted on c.t.t. June 19, 1998);
+ % /HLComment?\number`\x reads past one following space (expanding as it goes);
+ \long\def\TrimSpaces#1{\expandafter\TrimSpaces@i\number`\^^00#1| |}
+ % /HLComment?Remove the "0" produced by \number`\^^00, and " |" at the end.;
+ \long\def\TrimSpaces@i 0#1 |{\TrimSpaces@ii\empty#1|}
+ % /HLComment?" |" was removed by \TrimSpaces@i, now remove a trailing "||" or "| |";
+ \long\def\TrimSpaces@ii #1|#2|{#1}
+
+ \makeatother
+
+ \multido{\iString=1+1}{4}{%
+ \checkStrings(\iString)%
+ \BS\texttt{Strings(\iString)}=`\TrimSpaces{\cachedata}'\qquad}
+\end{Example}
+
+\begin{Description}{4cm}
+ \item[\FormatTeXMacro{check}] Get the content of the array element specified
+ by the indice(s) and store the result in the macro !\cachedata!
+
+ Syntax: !\check/Variable?ArrayName;(I)! or more generally
+ !\check/Variable?ArrayName;(I1,..,In)!
+
+ Example: !\checkActors(2)!
+ \item[\FormatTeXMacro{cachedata}] Macro where the content is stored after
+ a !\check! request.
+ \item[\FormatTeXMacro{ifemptydata}] True if the last \Macro{check} request
+ has given an empty result.
+\end{Description}
+
+\newarray\Values
+\readarray{Values}{A&B&C&D}
+
+\newarray\Actors
+\newarray\Dates
+\newarray\Sexes
+\readarray{Actors}{Louise Brooks&%
+ Marlene Dietrich&%
+ Clark Gable}
+\readarray{Dates}{1906--1985&%
+ 1902--1992&%
+ 1901--1960}
+\readarray{Sexes}{2&2&1}
+
+\begin{SideBySideExample}[xrightmargin=6cm]
+ % /HLComment?Plain TeX usage;
+ \checkValues(2)%
+ \verb+\Values(2)+ = `\cachedata'
+ Z\par
+ \checkActors(3)%
+ \verb+\Actors(3)+ = `\cachedata'
+ Z\par
+ \checkActors(5)%
+ \ifemptydata
+ \verb+\Actors(5)+ not defined.
+ \fi
+ Z\par
+ % /HLComment?LaTeX usage;
+ \newcommand{\IsEmptyElement}[2]{%
+ \ifthenelse{\boolean{emptydata}}{#1}{#2}}
+ \checkActors(3)%
+ \verb+\Actors(3)+ = \IsEmptyElement{not defined}{`\cachedata'}
+ Z\par
+ \checkActors(5)%
+ \verb+\Actors(5)+ \IsEmptyElement{not defined}{`\cachedata'}
+\end{SideBySideExample}
+
+\begin{Description}{4cm}
+ \item[\FormatTeXMacro{ifnormalindex}] See below (Default: !\normalindexfalse!).
+
+ \item[\FormatTeXMacro{dataheight}\label{par:DataHeight}] Counter containing
+ the number of elements in the first dimension, if arrays are bi-dimensional.
+
+ Syntax: !\dataheight=/Variable?Number;!
+
+ Remarks:
+ \begin{enumerate}
+ \item arrays are monodimensional when !\dataheight!~$\leq~1$,
+ \item if !\normalindexfalse! (which is the default value), we have:
+ $$\hspace{-3cm}\Macro{\Variable{ArrayName}}(I_1,...,I_n)
+ = \Macro{\Variable{ArrayName}}(I_n + (I_{n-1}-1) *
+ \Macro{dataheight} + \cdots
+ + (I_1-1) * \Macro{dataheight}^{n-1})$$
+
+ and if !\normalindextrue!, we have:
+ $$\hspace{-3cm}\Macro{\Variable{ArrayName}}(I_1,...,I_n)
+ = \Macro{\Variable{ArrayName}}(I_1 + (I_2-1) *
+ \Macro{dataheight} + \cdots
+ + (I_n-1) * \Macro{dataheight}^{n-1})$$
+ \end{enumerate}
+\end{Description}
+
+\begin{SideBySideExample}[xrightmargin=6cm]
+ \newarray\Letters
+ \readarray{/HLReverse?Letters;}{A&B&C&D&E&F&G&H&I&J}
+ \dataheight=5
+
+ Z\begin{tabular}{c|c|c|c|c|c|c|c|c|}
+ Z \multicolumn{1}{c}{} & \multicolumn{1}{c}{1} & \multicolumn{1}{c}{2} &
+ Z \multicolumn{1}{c}{3} & \multicolumn{1}{c}{4} & \multicolumn{1}{c}{5} \\ \cline{2-6}
+ Z 1 & A & B & C & D & E \\ \cline{2-6}
+ Z 2 & F & G & H & I & J \\ \cline{2-6}
+ Z\end{tabular}
+ Z\\[2mm]
+ % /HLComment?Default is \normalindexfalse;
+ \verb+\Letters(1,2)=+`\Letters(1,2)'
+ Z\par
+ \verb+\Letters(2,1)=+`\Letters(2,1)'
+ Z\\[2mm]
+ Z\begin{tabular}{c|c|c|}
+ Z \multicolumn{1}{c}{} & \multicolumn{1}{c}{1} & \multicolumn{1}{c}{2} \\ \cline{2-3}
+ Z 1 & A & F \\ \cline{2-3}
+ Z 2 & B & G \\ \cline{2-3}
+ Z 3 & C & H \\ \cline{2-3}
+ Z 4 & D & I \\ \cline{2-3}
+ Z 5 & E & J \\ \cline{2-3}
+ Z\end{tabular}
+ Z\\[2mm]
+ \normalindextrue
+ \verb+\Letters(1,2)=+`\Letters(1,2)'
+ Z\par
+ \verb+\Letters(2,1)=+`\Letters(2,1)'
+\end{SideBySideExample}
+
+\begin{Description}{4cm}
+ \item[\FormatTeXMacro{ifexpandarrayelement}] Boolean macro to allow or not
+ the element to be evaluated before to be stored in the array (Default:
+ !\expandarrayelementfalse!).
+
+ Syntax: !\expandarrayelementtrue! or !\expandarrayelementfalse!
+
+ Remark: take care to the possible side effects if you store some macros
+ as values of some array elements without evaluating them, as they can
+ change of content later... (see the following examples).
+\end{Description}
+
+\begin{SideBySideExample}[xrightmargin=6cm]
+ \newarray\Data
+ \newcount\CounterP % /HLComment?Plain TeX usage;
+ \CounterP=3
+ \newcounter{CounterL} % /HLComment?LaTeX usage;
+ \setcounter{CounterL}{3}
+ \def\Town{Madrid}
+ \Data(1)={\the\CounterP}
+ \Data(2)={\the\value{CounterL}}
+ \Data(3)={\Town}
+
+ \expandarrayelementtrue
+ \Data(4)={\the\CounterP}
+ \Data(5)={\the\value{CounterL}}
+ \Data(6)={\Town}
+
+ \CounterP=5
+ \setcounter{CounterL}{5}
+ \def\Town{Roma}
+
+ \multido{\iData=1+1}{6}{%
+ \BS\texttt{Data(\iData)}=`\Data(\iData)'\\}
+\end{SideBySideExample}
+
+\vspace{3mm}
+\noindent Some other macros exists for mono-dimensional arrays (and only for
+them), but have little additional interest:
+
+\begin{Description}{4cm}
+ \item[\FormatTeXMacro{array}] Store or get the content of the array element
+ specified by the index. In the last case, the content is inserted at the
+ current point.\footnote{The macro name \verb|\array| conflicts with macros in {\tt amsmath}. This is changed in version 1.04.}
+
+ Syntax: !\array/Parameter?/Variable?ArrayName;;(I)=/Parameter?/Variable?Content;;!
+ to store a value
+
+ \hspace{1.3cm}!\array/Parameter?/Variable?ArrayName;;(I)! to retrieve a value
+
+ Examples: !\array{Actors}(6)={Joan Crawford}!
+
+ \hspace{1.75cm}!\array{Actors}(3)!
+
+ \item[\FormatTeXMacro{clrarray}] Clear the content of the array element specified.
+ A following inquiry on this element will give an empty content.
+
+ Syntax: !\clrarray/Parameter?/Variable?ArrayName;;(I)!
+
+ Example: !\clrarray{Actors}(2)!
+
+ \item[\FormatTeXMacro{testarray}] Get the content of the array element specified
+ by the index and store the result in the macro !\temp@macro!%
+ \footnote{In \LaTeX, this macro should be used inside a package or between
+ the \verb+\makeatletter+ $\cdots$ \verb+\makeatother+ macro pair.}.
+
+ Syntax: !\testarray/Parameter?/Variable?ArrayName;;(I)!
+
+ Example: !\testarray{Actors}(1)\typeout{Actors(1)=`\temp@macro'}!
+\end{Description}
+
+\section{Examples}
+
+\UndefineShortVerb{\!} % We will use the ! character in the next examples
+
+ We will first show some basic and easy examples, before looking at more
+advanced ones to solve some complex problems, which require more knowledge of
+\TeX{} programming techniques.
+
+\subsection{Basic examples}
+
+ The immediate thing for which we can use arrays is to store and retrieve
+information:
+
+\vspace{2mm}
+\begin{SideBySideExample}[xrightmargin=6cm]
+ \newarray\Actors
+ \newarray\Dates
+ \newarray\Sexes
+
+ \readarray{/HLReverse?Actors;}{Louise Brooks&Marlene Dietrich&Clark Gable}
+ \readarray{/HLReverse?Dates;}{1906--1985&1902--1992&1901--1960}
+ \readarray{/HLReverse?Sexes;}{2&2&1}
+
+ \begin{description}
+ \item[\Actors(1)] : \Dates(1)
+ \item[\Actors(2)] : \Dates(2)
+ \item[\Actors(3)] : \Dates(3)
+ \end{description}
+\end{SideBySideExample}
+
+\vspace{2mm}
+ But we can also use a general loop macro, as the one provided by the
+\MultiDoPackage{} package, for more powerful usage and a management
+independent of the number of elements:
+
+\vspace{2mm}
+\begin{SideBySideExample}[xrightmargin=6cm]
+ \newcommand{\NumberActors}{3}
+
+ \begin{description}
+ \multido{\iActor=1+1}{\NumberActors}{%
+ \item[\Actors(\iActor)] : \Dates(\iActor)}
+ \end{description}
+\end{SideBySideExample}
+
+\vspace{2mm}
+ This allow various usage in the formatting of texts. A common usage is for a
+\emph{mailing} process, when we must compose some similar letters to various
+people (as we said previously, this was the reason for which these macros were
+developed in the \FormLettPackage{} package). Here, the usage of a programming
+language allow a great flexibility, using some conditionals to format the text
+differently or even to insert different pieces of text according to the person:
+
+\newcommand{\NumberActors}{3}
+
+\begin{CenterExample}
+ \newcounter{iActor}
+
+ \newcommand{\AccordingSexe}[2]{%
+ \checkSexes(\the\value{iActor})%
+ \ifthenelse{\equal{\cachedata}{1}}{#1}{#2}}
+
+ \whiledo{\value{iActor} < \NumberActors}{%
+ \stepcounter{iActor}%
+ \fbox{%
+ \begin{minipage}{0.985\textwidth}
+ Dear \AccordingSexe{Mr}{Mrs} \Actors(\the\value{iActor}),
+
+ I would like to tell you how I admire the great \AccordingSexe{actor}{actress}
+ you are, etc.
+ \end{minipage}}\\[5mm]}
+\end{CenterExample}
+
+ Nevertheless, people who know a little \TeX{} as a programming language know
+that it behaviour is full of pitfalls... For instance, the following example,
+which format a table according to the content of entries stored in external
+arrays, can't work:
+
+\begin{Verbatim}
+ \begin{tabular}{|l|c|}
+ \hline
+ \multicolumn{1}{|c}{\textbf{Actors}} & \multicolumn{1}{|c|}{\textbf{Dates}} \\ \hline
+ \multido{\iActor=1+1}{\NumberActors}{\Actors(\iActor) & \Dates(\iActor) \\ \hline}
+ \end{tabular}
+\end{Verbatim}
+
+ This is because there is an implicit grouping of each entry in a tabular
+environment and that it do not work with the grouping of the \verb+\multido+
+loop. So, this must be program in a different way, storing all the content of
+the table before really inserting it:
+
+\begin{SideBySideExample}[xrightmargin=6cm,baselinestretch=0.9]
+ \begin{tabular}{|l|c|}
+ \hline
+ \multicolumn{1}{|c}{\textbf{Actors}} &
+ \multicolumn{1}{|c|}{\textbf{Dates}} \\ \hline
+ \let\ListActors\empty
+ \begingroup
+ \let\Actors\relax
+ \let\Dates\relax
+ \let\\\relax
+ \let\hline\relax
+ \multido{\iActor=1+1}{\NumberActors}{%
+ \xdef\ListActors{\ListActors
+ \Actors(\iActor) & \Dates(\iActor) \\ \hline}}
+ \endgroup
+ \ListActors
+ \end{tabular}
+\end{SideBySideExample}
+
+\subsubsection{Plot labels}
+
+ A basic usage in graphic programming is to use arrays to retrieve the labels
+to put on a drawing, as here to label the simple plot below. (Note the change from the original documentation. The axis labels used with \verb|\psaxes| must now be numeric, so it is necessary to bypass the automatic axis labeling.)
+\ifpstricks % If PSTricks is available
+\begin{CenterExample}[baselinestretch=0.9]
+ \savedata{\Data}[(1,3)(2,1)(3,2)(4,1)(5,1)(6,3),(7,2)(8,1)(9,3)(10,3)(11,1)(12,1)]
+
+ \newcommand{\PlotData}[1]{%
+ \begin{pspicture}(-0.5,-0.5)(13,4)
+ \psaxes[labels=none]{->}(13,4)
+ \dataplot[plotstyle=dots,dotstyle=o,dotsize=0.3]{\Data}
+ #1\end{pspicture}}
+ \PlotData{\psaxes[showorigin=false]{->}(13,4)}
+
+ \newarray{\Months}
+ \readarray{/HLReverse?Months;}{January&February&March&April&May&June&July&August&September&%
+ October&November&December}
+ \newarray{\Levels}
+ \readarray{/HLReverse?Levels;}{Low&Medium&High}
+ %\renewcommand{\pshlabel}[1]{\tiny\Months(#1)}
+ \PlotData{\psaxes[labels=y,showorigin=false]{->}(13,4)%
+ \multido{\i=1+1}{12}{\rput[B](\i,-12pt){\tiny\Months(\i)}}}
+
+ %\renewcommand{\psvlabel}[1]{\small\Levels(#1)}
+ \PlotData{\multido{\i=1+1}{12}{\rput[B](\i,-12pt){\tiny\Months(\i)}}%
+ \multido{\i=1+1}{3}{\rput[r](-12pt,\i){\small\Levels(\i)}}}
+\end{CenterExample}
+\else
+ \PSTricksExampleNotShown
+\fi % End \pstrickstrue
+
+\subsubsection{Checkboard drawing}
+
+ Of course, a bi-dimensional array directly allow to store the state of a
+checkboard of one of the numerous ones existing, like the reversi game that
+we will show here (in fact, the only more difficult part to understand in this
+example concern the definition of the elementary piece, but as this is not
+related at all to the usage of \ArrayJobPackage, this point can be forgotten
+by most of the readers).
+
+\ifpstricks % If PSTricks is available
+\begin{SideBySideExample}[xrightmargin=6cm,baselinestretch=0.89]
+ /HLMacro?\def\Black;{B}
+ /HLMacro?\def\White;{W}
+
+ /HLMacro?\def\Piece;#1#2{{%
+ \psset{unit=0.8}%
+ \pspicture(0,-0.1)(1,0.8)
+ \pscustom[fillstyle=gradient,gradmidpoint=0,gradangle=90,
+ gradbegin=#2,gradend=#1]{%
+ \psbezier(0,0.2)(0.1,-0.2)(0.9,-0.2)(1,0.2)
+ \psline(1,0.2)(1,0.5)
+ \psbezier(1,0.5)(0.9,0.9)(0.1,0.9)(0,0.5)
+ \psline(0,0.5)(0,0.2)}
+ \psbezier(0,0.5)(0.1,0.1)(0.9,0.1)(1,0.5)
+ \endpspicture}}
+
+ /HLMacro?\def\PieceBlack;{\Piece{black}{gray}}
+ /HLMacro?\def\PieceWhite;{\Piece{white}{gray}}
+
+ /HLMacro?\def\CheckboardHook;{}
+
+ \newarray\Checkboard
+
+ /HLMacro?\def\ShowCheckboard;{%
+ \dataheight=8
+ \pspicture(8,8)
+ \psgrid[subgriddiv=0,gridlabels=0](8,8)
+ \CheckboardHook
+ \multido{\iColumn=1+1,\iColumnPos=0+1}{8}{%
+ \multido{\iRow=1+1,\iRowPos=7+-1}{8}{%
+ \checkCheckboard(\iRow,\iColumn)%
+ \ifx\cachedata\Black
+ \rput(\iColumnPos.5,\iRowPos.5){\PieceBlack}
+ \else
+ \ifx\cachedata\White
+ \rput(\iColumnPos.5,\iRowPos.5){\PieceWhite}
+ \fi
+ \fi}}
+ \endpspicture}
+
+ \readarray{/HLReverse?Checkboard;}{%
+ W& &B& & & & &B&%
+ &W&B& & & & &B&%
+ W&W&B& &W& & &B&%
+ W&W&B&W&W&W&B&B&%
+ B& &W&W&W&B&W&B&%
+ B&B&W&W&W&B&W&B&%
+ B&B&B&W&W&W&W&B&%
+ W&B&B&B&B&B&B&B&%
+ }
+
+ \psset{unit=0.6}
+ \ShowCheckboard
+
+ \Checkboard(2,1)={B} % /HLComment?Black move;
+ /HLMacro?\def\CheckboardHook;{%
+ \psframe[linestyle=none,fillstyle=hlines](0,6)(1,7)}
+ % /HLComment?White pieces changed by the black move;
+ \Checkboard(3,1)={B}\Checkboard(4,1)={B}
+ \Checkboard(2,2)={B}\Checkboard(3,2)={B}
+ \vspace{1cm}
+ \ShowCheckboard
+\end{SideBySideExample}
+\else
+ \PSTricksExampleNotShown
+\fi % End \pstrickstrue
+
+ Note also that, if \TeX{} is obviously not well suited to implement a
+program to \emph{really} play at a game like reversi or chess, nevertheless
+it can be used to solve internally some non trivial algorithmic problems,
+where the usage of arrays help a lot. For such example (on the coloration of
+the Truchet's tiling), see \cite{EG98}.
+
+\subsection{Advanced examples}
+
+ This section will show slightly more difficult to really complex examples,
+and is mainly for \emph{advanced users} or for people who want to be able to
+program complex tasks themselves.
+
+\subsubsection{Example with recursion usage}
+
+\begin{CenterExample}
+ \makeatletter
+
+ % /HLComment?The recursion macro used (from David Carlisle);
+ /HLMacro?\def\Recursion;#1{%
+ #1\relax
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi}
+
+ \newcount\IndexRecursion
+ \IndexRecursion=\z@
+
+ /HLMacro?\def\PiFrac;#1{{%
+ \Recursion
+ {\ifnum#1>\@ne\relax}
+ {\@tempcnta=#1
+ \advance\@tempcnta\m@ne
+ \advance\IndexRecursion\@ne
+ \PiValues(\IndexRecursion)
+ +\frac{\strut\displaystyle 1}{\strut\displaystyle\PiFrac{\@tempcnta}}}
+ {\advance\IndexRecursion\@ne
+ \PiValues(\IndexRecursion)}}}
+
+ \makeatother
+
+ \newarray\PiValues
+ \readarray{/HLReverse?PiValues;}{3&7&15&1&292&1&1&1&2&1&3&1&14}
+
+ \(\pi\approx\PiFrac{/HLReverse?4;}\approx\PiFrac{/HLReverse?13;}\)
+
+ \textbf{\(\pi\) as a continued fraction}
+\end{CenterExample}
+
+\subsubsection{Structured dynamic diagrams on a grid}
+
+ A very common case is when we must use some strutured data which are to be
+drawn on a kind of abstract grid.
+
+\ifpstricks % If PSTricks is available
+ To draw a diagram like this one (such example illustrate the exchanges of
+data between processors when using applications on multiprocessors computers
+in parallel programming):
+
+\vspace{2mm}
+\begin{SideBySideExample}[xrightmargin=5.8cm]
+ \psset{linestyle=none,fillstyle=solid,subgriddiv=0,gridlabels=0}
+ \begin{pspicture}(-1,0)(4,4)
+ % /HLComment?Line 0;
+ \psframe[fillcolor=Khaki](0,3.1)(1,3.9)
+ \psframe[fillcolor=LemonChiffon](1,3.1)(4,3.9)
+ \rput(0,3.1){\psgrid[yunit=0.8](4,1)}
+ \rput(-0.5,3.5){P0}
+ \rput(0.5,3.5){A0}
+ % /HLComment?Line 1;
+ \psframe[fillcolor=Khaki](0,2.1)(2,2.9)
+ \psframe[fillcolor=LemonChiffon](2,2.1)(4,2.9)
+ \rput(0,2.1){\psgrid[yunit=0.8](4,1)}
+ \rput(-0.5,2.5){P1}
+ \rput(0.5,2.5){A0}\rput(1.5,2.5){A1}
+ % /HLComment?Line 2;
+ \psframe[fillcolor=Khaki](0,1.1)(3,1.9)
+ \psframe[fillcolor=LemonChiffon](3,1.1)(4,1.9)
+ \rput(0,1.1){\psgrid[yunit=0.8](4,1)}
+ \rput(-0.5,1.5){P2}
+ \rput(0.5,1.5){A0}\rput(1.5,1.5){A1}\rput(2.5,1.5){A2}
+ % /HLComment?Line 3;
+ \psframe[fillcolor=Khaki](0,0.1)(4,0.9)
+ \rput(0,0.1){\psgrid[yunit=0.8](4,1)}
+ \rput(-0.5,0.5){P3}
+ \rput(0.5,0.5){A0}\rput(1.5,0.5){A1}
+ \rput(2.5,0.5){A2}\rput(3.5,0.5){A3}
+ \end{pspicture}
+\end{SideBySideExample}
+
+\vspace{2mm}
+\noindent is easy but rather painful, as we must manage a lot of coordinates.
+Nevertheless, even if we introduce a little more abstraction level using some
+minor programming with a loop structure:
+\vspace{2mm}
+
+
+\begin{SideBySideExample}[xrightmargin=5.8cm]
+ \psset{linestyle=none,fillstyle=solid,subgriddiv=0,gridlabels=0}
+ \begin{pspicture}(-1,0)(4,4)
+ \multido{\iLoop=1+1,\iRow=0+1,\iRowPos=3+-1}{4}{%
+ \psframe[fillcolor=Khaki](0,\iRowPos.1)(\iLoop,\iRowPos.9)
+ \psframe[fillcolor=LemonChiffon]
+ (\iLoop,\iRowPos.1)(4,\iRowPos.9)
+ \rput(0,\iRowPos.1){\psgrid[yunit=0.8](4,1)}
+ \rput(-0.5,\iRowPos.5){P\iRow}
+ \multido{\iColumn=0+1,\iLabel=1+1}{\iLoop}{%
+ \rput(\iColumn.5,\iRowPos.5){A\iColumn}}}
+ \end{pspicture}
+\end{SideBySideExample}
+
+\vspace{2mm}
+\noindent we succeed to heavily reduce the number of lines of the code in this
+specific case, but we gain nothing in genericity. If we have several such
+diagrams to draw, with each that must be done differently according to the
+empty and full cells of the array, we must proceed in a completely different
+way, defining a \emph{generic object} which can obtain the different values of
+a data structure previously filled. For such tasks, the \ArrayJobPackage{}
+package allow to build very efficient and powerful tools.
+
+\begin{Verbatim}[commandchars=/?;]
+ % /HLComment?The grid;
+ /HLMacro?\def\ArrayGrid;#1#2#3{{%
+ % /HLComment?#1=array of data, #2=number of rows, #3=number of columns;
+ \psset{dimen=middle,xunit=0.8}
+ \dataheight=#3
+ \pspicture(-1,-#2)(#3,0)
+ \multido{\iRow=1+1,\iRowMinusOne=0+1}{#2}{%
+ \rput(-1,-\iRow){\LineGrid{#1}{\iRow}{\iRowMinusOne}{#3}}}
+ \endpspicture}}
+
+ % /HLComment?One line of the grid;
+ /HLMacro?\def\LineGrid;#1#2#3#4{%
+ \rput(0.5,0.4){\AttributeLabel{P#3}}
+ \multido{\iColumn=1+1}{#4}{%
+ \expandafter\csname check#1\endcsname(#2,\iColumn)%
+ \rput(\iColumn,0){%
+ \ifemptydata
+ \def\ColorBackground{\ColorBackgroundEmpty}%
+ \else
+ \ifx\cachedata\space
+ \def\ColorBackground{\ColorBackgroundEmpty}%
+ \else
+ \def\ColorBackground{\ColorBackgroundFull}%
+ \fi
+ \fi
+ \psframe[fillstyle=solid,fillcolor=\ColorBackground](1,0.8)
+ \rput(0.5,0.4){\AttributeElement{\cachedata}}}}}
+\end{Verbatim}
+
+% The grid
+\def\ArrayGrid#1#2#3{{%
+% #1=array of data, #2=number of rows, #3=number of columns
+\psset{dimen=middle,xunit=0.8}
+\dataheight=#3
+\pspicture(-1,-#2)(#3,0)
+\multido{\iRow=1+1,\iRowMinusOne=0+1}{#2}{%
+ \rput(-1,-\iRow){\LineGrid{#1}{\iRow}{\iRowMinusOne}{#3}}}
+\endpspicture}}
+
+% One line of the grid
+\def\LineGrid#1#2#3#4{%
+\rput(0.3,0.4){\AttributeLabel{P#3}}
+\multido{\iColumn=1+1}{#4}{%
+ \expandafter\csname check#1\endcsname(#2,\iColumn)%
+ \rput(\iColumn,0){%
+ \ifemptydata
+ \def\ColorBackground{\ColorBackgroundEmpty}%
+ \else
+ \ifx\cachedata\space
+ \def\ColorBackground{\ColorBackgroundEmpty}%
+ \else
+ \def\ColorBackground{\ColorBackgroundFull}%
+ \fi
+ \fi
+ \psframe[fillstyle=solid,fillcolor=\ColorBackground](1,0.8)
+ \rput(0.5,0.4){\AttributeElement{\cachedata}}}}}
+
+\begin{SideBySideExample}[xrightmargin=6cm]
+ % /HLComment?Default attributes;
+ \def\ColorBackgroundEmpty{LemonChiffon}
+ \def\ColorBackgroundFull{Khaki}
+ \def\AttributeElement#1{\textcolor{red}{#1}}
+ \def\AttributeLabel#1{\bf #1}
+
+ % /HLComment?Example 1;
+ \newarray\ArrayA
+
+ % /HLComment?Data;
+ \readarray{/HLReverse?ArrayA;}{%
+ A0& & & &%
+ A0&A1& & &%
+ A0&A1&A2& &%
+ A0&A1&A2&A3}
+
+ \ArrayGrid{ArrayA}{4}{4}
+\end{SideBySideExample}
+
+\newarray\ArrayA
+
+% Default attributes
+\def\ColorBackgroundEmpty{LemonChiffon}
+\def\ColorBackgroundFull{Khaki}
+\def\AttributeElement#1{\textcolor{red}{#1}}
+\def\AttributeLabel#1{\bf #1}
+
+\begin{CenterExample}[baselinestretch=0.9]
+ % /HLComment?Example 2;
+ \newarray\ArrayB
+
+ % /HLComment?Data;
+ \readarray{/HLReverse?ArrayA;}{%
+ A& & & &%
+ & & & &%
+ & & & &%
+ & & & }
+ \readarray{/HLReverse?ArrayB;}{%
+ A& & & &%
+ A& & & &%
+ A& & & &%
+ A& & & }
+
+ \ArrayGrid{ArrayA}{4}{4}\hfill\ArrayGrid{ArrayB}{4}{4}
+\end{CenterExample}
+
+\newarray\ArrayB
+
+\begin{CenterExample}[baselinestretch=0.9]
+ % /HLComment?Example 3;
+ \newarray\ArrayC
+
+ % /HLComment?Data;
+ \readarray{/HLReverse?ArrayA;}{%
+ A0& & &%
+ A1& & &%
+ A2& & }
+ \readarray{/HLReverse?ArrayB;}{%
+ A0&A1&A2&%
+ A0&A1&A2&%
+ A0&A1&A2}
+ \readarray{/HLReverse?ArrayC;}{%
+ A0& & &%
+ &A1& &%
+ & &A2}
+
+ % /HLComment?Attributes;
+ \def\ColorBackgroundEmpty{green}
+ \def\ColorBackgroundFull{red}
+ \def\AttributeElement#1{\footnotesize\textcolor{white}{#1}}
+ \def\AttributeLabel#1{\small\bf #1}
+
+ \psset{unit=0.7}
+ \ArrayGrid{ArrayA}{3}{3}\hfill\ArrayGrid{ArrayB}{3}{3}\hfill\ArrayGrid{ArrayC}{3}{3}
+\end{CenterExample}
+
+\begin{CenterExample}[baselinestretch=0.9]
+ % /HLComment?Example 4;
+
+ % /HLComment?Data;
+ \readarray{/HLReverse?ArrayA;}{%
+ A0&A1&A2&A3&%
+ B0&B1&B2&B3&%
+ C0&C1&C2&C3&%
+ D0&D1&D2&D3}
+ \readarray{/HLReverse?ArrayB;}{%
+ A0&B0&C0&D0&%
+ A1&B1&C1&D1&%
+ A2&B2&C2&D2&%
+ A3&B3&C3&D3}
+
+ % /HLComment?Attributes;
+ \def\AttributeElement#1{\textcolor{red}{#1}}
+ \def\AttributeLabel#1{\Large\it #1}
+
+ \ArrayGrid{ArrayA}{4}{4}\hfill\ArrayGrid{ArrayB}{4}{4}
+\end{CenterExample}
+\else
+ \PSTricksExampleNotShown
+\fi % End \pstrickstrue
+
+\vspace{5mm}
+\subsubsection{Another example of a structured dynamic diagram on a grid}
+
+ The preceding technique is in fact relevant for a lot of problems. Here we
+give another example about the drawing of linked lists (but do not fail to
+note that these ones have here no internal existence).
+
+\ifpstricks % If PSTricks is available
+\begin{CenterExample}
+ \makeatletter
+
+ \newpsstyle{LinkedListsArrowStyle}{linecolor=red,arrowscale=2} % /HLComment?Default arrow style;
+
+ /HLMacro?\def\LinkedListsDraw;{\@ifnextchar[\LinkedListsDraw@i{\LinkedListsDraw@i[]}}
+
+ /HLMacro?\def\LinkedListsDraw@i;[#1]#2#3{{%
+ \setkeys{psset}{#1}
+ \dataheight=#3
+ %
+ \pst@cnta=#3
+ \multiply\pst@cnta\tw@
+ \advance\pst@cnta\tw@
+ \pspicture(0,-#2)(\pst@cnta,0)
+ \multido{\iRow=1+1}{#2}{%
+ \rput(0,-\iRow){%
+ \psframe(1,1)
+ \psline[dimen=middle,style=LinkedListsArrowStyle]{->}(0.5,0.5)(2,0.5)}
+ \multido{\iColumn=1+1}{#3}{%
+ \checkLinkedListsTable(\iRow,\iColumn)%
+ \ifemptydata
+ \else
+ \pst@cnta=\iColumn
+ \advance\pst@cnta\@ne
+ \pst@cntb=\@ne
+ \checkLinkedListsTable(\iRow,\pst@cnta)%
+ \ifemptydata % /HLComment?We test if it is empty;
+ \else
+ \ifnum\multidocount=#3 % /HLComment?We test if it is the last one;
+ \else
+ \pst@cntb=\z@
+ \fi
+ \fi
+ %
+ \pst@cnta=\iColumn
+ \multiply\pst@cnta\tw@
+ \rput(\the\pst@cnta,-\iRow){%
+ \LinkedListsDraw@ii{\LinkedListsTable(\iRow,\iColumn)}{\the\pst@cntb}}
+ \fi}}
+ \endpspicture}}%}
+
+ /HLMacro?\def\LinkedListsDraw@ii;#1#2{{%
+ \rput(0,0.1){%
+ \psset{unit=0.8}
+ \psgrid[subgriddiv=0,gridlabels=0](2,1) % /HLComment?Element;
+ \rput(0.5,0.5){#1} % /HLComment?Label for this element;
+ \ifnum#2=\@ne
+ \psline(1,0)(2,1) % /HLComment?Mark of the end of the list;
+ \else
+ \psline[style=LinkedListsArrowStyle]{->}(1.5,0.5)(2.5,0.5) % /HLComment?Link to the next element;
+ \fi}}}
+
+ \makeatother
+
+ \newarray\LinkedListsTable
+ \readarray{/HLReverse?LinkedListsTable;}{%
+ 11&12&13&14&%
+ 21&&&&%
+ 31&32&33&&}
+
+ \LinkedListsDraw{3}{4}
+
+ \vspace{1cm}
+ \newpsstyle{LinkedListsArrowStyle}{linecolor=green,doubleline=true}
+
+ \readarray{/HLReverse?LinkedListsTable;}{%
+ a&&&&&%
+ A&B&C&D&E&%
+ 0&1&2&3&4&%
+ +&$\times$&&&&}
+
+ \LinkedListsDraw{4}{5}
+\end{CenterExample}
+\else
+ \PSTricksExampleNotShown
+\fi % End \pstrickstrue
+
+\subsubsection{Management of heaps and linked lists}
+
+ Here we will demonstrate a really more complex usage, but very useful.
+In fact, if the \ArrayJobPackage{} package primarily allow to manage only
+arrays, it allow a lot more with some efforts. Above it, we can implement the
+common internal data structures frequently used in programming, like heaps,
+simple or double linked lists, trees, associative arrays, etc. Here we will
+show how to define macros to build and manage heaps and simple linked lists.
+
+\ifpstricks % If PSTricks is available
+\vspace{1cm} % Poor hack to force a page break...
+\begin{CenterExample}[baselinestretch=0.98]
+ \makeatletter
+
+ /HLMacro?\def\PstDebug;{\z@} % /HLComment?For debugging, set \def\PstDebug{1};
+
+ % /HLComment?Code for heaps management;
+ % /HLComment?-------------------------;
+
+ /HLMacro?\def\HeapMaxDepth;{100} % /HLComment?No more than 100 elements in the heap;
+
+ \newarray\Heap
+
+ % /HLComment?Add an element at top of the heap;
+ /HLMacro?\def\HeapPush;#1{%
+ \multido{\iElem=1+1}{\HeapMaxDepth}{%
+ \checkHeap(\iElem)%
+ \ifemptydata
+ \ifnum\PstDebug=\@ne\typeout{Push Heap(\iElem)=#1}\fi% /HLComment?Debug;
+ \Heap(\iElem)={#1}%
+ \multidostop
+ \fi}}
+
+ % /HLComment?Get (in the \cachedata macro) and delete the element at top of the heap;
+ /HLMacro?\def\HeapPop;{%
+ \Multido{\iElem=\HeapMaxDepth+-1}{\HeapMaxDepth}{%
+ \checkHeap(\iElem)%
+ \ifemptydata
+ \else
+ \ifnum\PstDebug=\@ne\typeout{Delete Heap(\iElem)=\cachedata}\fi% /HLComment?Debug;
+ \Heap(\iElem)={}%
+ \multidostop
+ \fi}}
+
+ % /HLComment?Print the current state of the heap;
+ /HLMacro?\def\HeapPrint;{%
+ \checkHeap(\@ne)%
+ \ifemptydata
+ \typeout{The heap is empty!}% /HLComment?Empty heap;
+ \else
+ \multido{\iElem=\HeapMaxDepth+-1}{\HeapMaxDepth}{%
+ \checkHeap(\iElem)%
+ \ifemptydata
+ \else
+ \typeout{Heap(\iElem)=\cachedata}%
+ \fi}
+ \fi
+ \typeout{}}
+
+ % /HLComment?Draw the current state of the heap;
+ /HLMacro?\def\HeapDraw;{%
+ % /HLComment?To compute the size of the picture;
+ \Multido{\iSize=0+1}{\HeapMaxDepth}{%
+ \checkHeap(\the\multidocount)%
+ \ifemptydata
+ \multidostop
+ \fi}
+ %
+ \ifnum\iSize=\z@
+ % /HLComment?Empty heap;
+ \typeout{The heap is empty!^^J}%
+ \else
+ \pspicture(1,\iSize)
+ \psgrid[subgriddiv=0,gridlabels=0](1,\iSize)
+ \multido{\iPos=0+1}{\HeapMaxDepth}{%
+ \checkHeap(\the\multidocount)%
+ \ifemptydata
+ \multidostop
+ \else
+ \rput(0.5,\iPos.5){\cachedata}
+ \fi}
+ \endpspicture%
+ \fi}
+
+ \makeatother
+
+ \psset{unit=1.5}\footnotesize
+
+ \HeapPush{Germany}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPush{France}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPush{Italy}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPush{Spain}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPop\typeout{Popped element: `\cachedata'}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPop\typeout{Popped element: `\cachedata'}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPop\typeout{Popped element: `\cachedata'}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPop\typeout{Popped element: `\cachedata'}\HeapPrint\HeapDraw
+\end{CenterExample}
+
+\begin{Example}[baselinestretch=0.95]
+ \makeatletter
+
+ /HLMacro?\def\PstDebug;{\z@}% /HLComment?For debugging, set \def\PstDebug{1};
+
+ % /HLComment?Code for linked lists management;
+ % /HLComment?--------------------------------;
+
+ /HLMacro?\def\LinkedListMaxDepth;{100}% /HLComment?No more than 100 elements in the list;
+
+ \newarray\LinkedList
+
+ \dataheight=2% /HLComment?Two cells by element: the content and the pointer;
+
+ % /HLComment?Add an element at the end of the list;
+ % /HLComment?In fact, we define it here as a simple heap, but the difference is that;
+ % /HLComment?we will be able to get and to delete any element in it;
+ /HLMacro?\def\LinkedListAdd;#1{%
+ \edef\@tempa{\@ne}% /HLComment?Pointer initialization;
+ \multido{\iElem=2+1}{\LinkedListMaxDepth}{%
+ \checkLinkedList(\@tempa,2)% /HLComment?We got the content of this element;
+ \ifemptydata
+ % /HLComment?No pointed element, so we will insert the new one here;
+ \LinkedList(\iElem,1)={#1}%
+ % /HLComment?We update the pointer for the last preceding element;
+ \expandarrayelementtrue% /HLComment?We must evaluate the content of the counter;
+ \LinkedList(\@tempa,2)={\iElem}%
+ \expandarrayelementfalse
+ \ifnum\PstDebug=\@ne
+ \typeout{Add LinkedList(\@tempa)->\iElem}% /HLComment?Debug;
+ \typeout{\space\space\space\space LinkedList(\iElem)=#1}% /HLComment?Debug;
+ \fi
+ \multidostop
+ \else
+ \edef\@tempa{\cachedata}%
+ \fi}}
+
+ % /HLComment?Get (in the \cachedata macro) the next element in the list;
+ /HLMacro?\def\LinkedListGetNext;#1{%
+ \checkLinkedList(1,2)% /HLComment?We got the pointer for the first element;
+ \edef\@tempa{\@ne}%
+ \ifx\cachedata\empty
+ \else
+ \edef\@tempc{#1}%
+ \Multido{}{\LinkedListMaxDepth}{%
+ \edef\@tempb{\@tempa}%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% /HLComment?We got the pointed element;
+ \ifx\cachedata\@tempc
+ % /HLComment?This is the element for which we want the next one: we got it pointer;
+ % /HLComment?to the next element in the list, then the content of it;
+ \checkLinkedList(\@tempa,2)%
+ \ifemptydata
+ \typeout{Element `#1' has no successor!^^J}%
+ \else
+ \checkLinkedList(\cachedata,1)%
+ \fi
+ \multidostop
+ \else
+ \checkLinkedList(\@tempa,2)% /HLComment?We got the pointer to the next element;
+ \ifemptydata
+ % /HLComment?We have reach the end of the list without finding the element;
+ \typeout{Element `#1' not found!^^J}%
+ \multidostop% /HLComment?No pointed element: end of the list;
+ \fi
+ \fi}
+ \fi}
+
+ % /HLComment?Delete an element in the list (the code is very close to \LinkedListGetNext);
+ /HLMacro?\def\LinkedListDelete;#1{%
+ \checkLinkedList(1,2)% /HLComment?We got the pointer for the first element;
+ \edef\@tempa{\@ne}%
+ \ifx\cachedata\empty
+ \else
+ \edef\@tempc{#1}%
+ \multido{}{\LinkedListMaxDepth}{%
+ \edef\@tempb{\@tempa}%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% /HLComment?We got the pointed element;
+ \ifx\cachedata\@tempc
+ % /HLComment?This is the element to delete: we will update the pointer of;
+ % /HLComment?the preceding element to the value of the pointer of the deleted one;
+ \checkLinkedList(\@tempa,2)%
+ \expandarrayelementtrue
+ \LinkedList(\@tempb,2)={\cachedata}%
+ \expandarrayelementfalse
+ \ifnum\PstDebug=\@ne
+ \typeout{Delete LinkedList(\@tempa)=#1}% /HLComment?Debug;
+ \typeout{\space\space\space\space\space\space\space %
+ LinkedList(\@tempb)->\cachedata}% /HLComment?Debug;
+ \fi
+ \multidostop
+ \else
+ \checkLinkedList(\@tempa,2)% /HLComment?We got the pointer to the next element;
+ \ifemptydata
+ % /HLComment?We have reach the end of the list without finding the element;
+ \typeout{Element `#1' not found and so not deleted!^^J}%
+ \multidostop% /HLComment?No pointed element: end of the list;
+ \fi
+ \fi}
+ \fi}
+
+ % /HLComment?Print the current state of the list;
+ /HLMacro?\def\LinkedListPrint;{%
+ \checkLinkedList(1,2)% /HLComment?We got the pointer for the first element;
+ \ifx\cachedata\empty
+ % /HLComment?Empty list;
+ \typeout{The list is empty!}%
+ \else
+ \multido{}{\LinkedListMaxDepth}{%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% /HLComment?We got the pointed element;
+ \typeout{LinkedList=\cachedata}%
+ \checkLinkedList(\@tempa,2)% /HLComment?We got the pointer to the next element;
+ \ifemptydata
+ \multidostop% /HLComment?No pointed element: end of the list;
+ \fi}
+ \fi
+ \typeout{}}
+
+ % /HLComment?Draw the current state of the list;
+ /HLMacro?\def\LinkedListDraw;{{%
+ \psset{subgriddiv=0,gridlabels=0}
+ \checkLinkedList(1,2)% /HLComment?We got the pointer for the first element;
+ \ifx\cachedata\empty
+ % /HLComment?Empty list;
+ \typeout{The list is empty!^^J}%
+ \else
+ % /HLComment?To compute the size of the picture;
+ \Multido{\iSize=3+3}{\LinkedListMaxDepth}{%
+ \checkLinkedList(\cachedata,2)% /HLComment?We got the pointer to the next element;
+ \ifemptydata
+ \multidostop
+ \fi}
+ %
+ \checkLinkedList(1,2)% /HLComment?We got the pointer for the first element;
+ \pspicture(\iSize,1.5)
+ \multido{\iPos=0+3}{\LinkedListMaxDepth}{%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% /HLComment?We got the pointed element;
+ \rput(\iPos,0){%
+ \psgrid(2,1)
+ \rput(0.5,0.5){\cachedata}
+ \ifnum\iPos=\z@
+ \else
+ \rput(-1.5,0.5){\psline[linecolor=red,arrowscale=2]{->}(1.5,0)}
+ \fi}
+ \checkLinkedList(\@tempa,2)% /HLComment?We got the pointer to the next element;
+ \ifemptydata
+ \rput(\iPos,0){\psline[linecolor=red](1,0)(2,1)} % /HLComment?End of the list;
+ \multidostop% /HLComment?No pointed element: end of the list;
+ \fi}
+ \endpspicture%
+ \fi}}
+
+ \makeatother
+
+ \psset{unit=1.5}
+
+ \LinkedListPrint\LinkedListDraw
+
+ \LinkedListAdd{Germany}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListAdd{France}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListAdd{Italy}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListAdd{Spain}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListGetNext{France}\typeout{Next element after `France' is: `\cachedata'}%
+ \LinkedListGetNext{Germany}\typeout{Next element after `Germany is: `\cachedata'}%
+ \LinkedListGetNext{Spain}
+ \LinkedListGetNext{Unknown}
+
+ \LinkedListDelete{Unknown}
+
+ \LinkedListDelete{France}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{Germany}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{Spain}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{Italy}\LinkedListPrint\LinkedListDraw
+\end{Example}
+
+\makeatletter
+
+\def\PstDebug{\z@}% For debugging, set \def\PstDebug{1}
+
+\def\LinkedListMaxDepth{100}% No more than 100 elements in the heap
+
+\newarray\LinkedList
+
+\dataheight=2% Two cells by element: the content and the pointer
+
+% Delete an element in the list
+\def\LinkedListDelete#1{%
+\checkLinkedList(1,2)% We got the pointer for the first element
+\edef\@tempa{\@ne}%
+\ifx\cachedata\empty
+\else
+ \edef\@tempc{#1}%
+ \multido{}{\LinkedListMaxDepth}{%
+ \edef\@tempb{\@tempa}%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% We got the pointed element
+ \ifx\cachedata\@tempc
+ % This is the element to delete: we will update the pointer of
+ % the preceding element to the value of the pointer of the deleted one
+ \checkLinkedList(\@tempa,2)%
+ \expandarrayelementtrue
+ \LinkedList(\@tempb,2)={\cachedata}%
+ \expandarrayelementfalse
+ \ifnum\PstDebug=\@ne
+ \typeout{Delete LinkedList(\@tempa)=#1}%Debug
+ \typeout{\space\space\space\space\space\space\space %
+ LinkedList(\@tempb)->\cachedata}%Debug
+ \fi
+ \multidostop
+ \else
+ \checkLinkedList(\@tempa,2)% We got the pointer to the next element
+ \ifemptydata
+ % We have reach the end of the list without finding the element
+ \typeout{Element `#1' not found and so not deleted!^^J}%
+ \multidostop% No pointed element: end of the list
+ \fi
+ \fi}
+\fi}
+
+% Print the current state of the list
+\def\LinkedListPrint{%
+\checkLinkedList(1,2)% We got the pointer for the first element
+\ifx\cachedata\empty
+ % Empty list
+ \typeout{The list is empty!}%
+\else
+ \multido{}{\LinkedListMaxDepth}{%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% We got the pointed element
+ \typeout{LinkedList=\cachedata}%
+ \checkLinkedList(\@tempa,2)% We got the pointer to the next element
+ \ifemptydata
+ \multidostop% No pointed element: end of the list
+ \fi}
+\fi
+\typeout{}}
+
+% Draw the current state of the list
+\def\LinkedListDraw{{%
+\psset{subgriddiv=0,gridlabels=0}
+\checkLinkedList(1,2)% We got the pointer for the first element
+\ifx\cachedata\empty
+ % Empty list
+ \typeout{The list is empty!^^J}%
+\else
+ % To compute the size of the picture
+ \Multido{\iSize=3+3}{\LinkedListMaxDepth}{%
+ \checkLinkedList(\cachedata,2)% We got the pointer to the next element
+ \ifemptydata
+ \multidostop
+ \fi}
+ %
+ \checkLinkedList(1,2)% We got the pointer for the first element
+ \pspicture(\iSize,1.5)
+ \multido{\iPos=0+3}{\LinkedListMaxDepth}{%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% We got the pointed element
+ \rput(\iPos,0){%
+ \psgrid(2,1)
+ \rput(0.5,0.5){\cachedata}
+ \ifnum\iPos=\z@
+ \else
+ \rput(-1.5,0.5){\psline[linecolor=red,arrowscale=2]{->}(1.5,0)}
+ \fi}
+ \checkLinkedList(\@tempa,2)% We got the pointer to the next element
+ \ifemptydata
+ \rput(\iPos,0){\psline[linecolor=red](1,0)(2,1)} % End of the list
+ \multidostop% No pointed element: end of the list
+ \fi}
+ \endpspicture%
+\fi}}
+
+\makeatother
+
+% We clear the linked list
+\multido{\iElem=1+1}{\LinkedListMaxDepth}{%
+ \checkLinkedList(\iElem,1)%
+ \ifemptydata
+ \else
+ \LinkedList(\iElem,1)={}%
+ \LinkedList(\iElem,2)={}%
+ \fi}
+
+\vspace{2mm}
+ We can write an extended version of the inclusion of an element, where we do
+not still store each element at the end of the list, but insert it at a
+special position. For instance, we can decide to use the list to sort the
+elements, inserting a new one at it sorted position. In the next example, we
+will manage integer numbers in this way (of course, we can do the same thing
+with arbitrary strings, but it would be more difficult to program in \TeX{},
+mainly if we want to be able to use accentuated letters).
+
+\vspace{2mm}
+\begin{Example}
+ \makeatletter
+
+ % /HLComment?Add an element at the end of the list, linked in it ordered place;
+ % /HLComment?(this version work only with contents as numbers);
+ /HLMacro?\def\LinkedListSortedAdd;#1{%
+ % /HLComment?Initializations;
+ \edef\@tempa{\@ne}%
+ \edef\@tempb{\@ne}%
+ \edef\@tempc{\z@}%
+ %
+ \multido{\iElem=2+1}{\LinkedListMaxDepth}{%
+ \checkLinkedList(\@tempa,2)% /HLComment?We got the pointer of this element;
+ \ifemptydata
+ % /HLComment?No pointed element, so we will insert the new one here;
+ \LinkedList(\iElem,1)={#1}%
+ % /HLComment?We update the pointer for the last element;
+ \expandarrayelementtrue
+ \LinkedList(\@tempb,2)={\iElem}%
+ \ifnum\PstDebug=\@ne
+ \typeout{Add LinkedList(\@tempb)->\iElem}% /HLComment?Debug;
+ \typeout{\space\space\space\space LinkedList(\iElem)=#1}% /HLComment?Debug;
+ \fi
+ % /HLComment?We update the pointer of the new element to the position;
+ % /HLComment?of the next greater one, if it exist;
+ \ifnum\@tempc=\z@
+ \else
+ \LinkedList(\iElem,2)={\@tempc}%
+ \ifnum\PstDebug=\@ne
+ \typeout{Update LinkedList(\iElem)->\@tempc}% /HLComment?Debug;
+ \fi
+ \fi
+ \expandarrayelementfalse
+ \multidostop
+ \else
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)%
+ \ifnum#1<\cachedata
+ \edef\@tempc{\@tempa}% /HLComment?New element less than this one;
+ \else
+ \edef\@tempb{\@tempa}% /HLComment?New element greater or equal than this one;
+ \fi
+ \fi}}
+
+ \makeatother
+
+ \LinkedListPrint
+
+ \LinkedListSortedAdd{732}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListSortedAdd{487}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListSortedAdd{718}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListSortedAdd{962}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{487}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{732}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{500}
+
+ \LinkedListDelete{962}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{718}\LinkedListPrint\LinkedListDraw
+\end{Example}
+\else
+ \PSTricksExampleNotShown
+\fi % End \pstrickstrue
+
+\subsubsection{Associative arrays}
+
+ To finish, we will give a complete solution to a classical problem: to count
+the number of occurrences of the various letters in a sentence. For this, we
+will first build some macros to deal with \emph{associative} arrays, as they
+have been popularized by scripting languages like \texttt{AWK} and
+\texttt{Perl}.
+
+\begin{Example}
+ \makeatletter
+
+ % /HLComment?Internally, we use two "standard" arrays to define one associative array;
+ \newarray\AssociativeArray@Names
+ \newarray\AssociativeArray@Values
+
+ \newcount\AssociativeArrayNbValues
+ \AssociativeArrayNbValues=\z@
+
+ \newif\ifAssociativeArray@ElementFound
+
+ % /HLComment?To store one element;
+ /HLMacro?\def\AssociativeArray;(#1)=#2{%
+ \expandarrayelementtrue
+ \AssociativeArray@ElementFoundfalse
+ \edef\@tempa{#1}%
+ \Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \ifx\@tempa\cachedata
+ % /HLComment?This element already exist: we replace it current value;
+ % /HLComment?\checkAssociativeArray@Values(\iValue)% Debug;
+ % /HLComment?\typeout{In #1, replace `\cachedata'\space by `#2'}% Debug;
+ \AssociativeArray@Values(\iValue)={#2}%
+ \AssociativeArray@ElementFoundtrue
+ \multidostop
+ \fi}
+ \ifAssociativeArray@ElementFound
+ \else
+ % /HLComment?New element;
+ \advance\AssociativeArrayNbValues\@ne
+ \AssociativeArray@Names(\AssociativeArrayNbValues)={#1}%
+ \AssociativeArray@Values(\AssociativeArrayNbValues)={#2}%
+ \fi}
+
+ % /HLComment?To get one element;
+ /HLMacro?\def\checkAssociativeArray;(#1){%
+ \edef\@tempa{#1}%
+ \edef\@tempb{999999}%
+ \Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \ifx\@tempa\cachedata
+ % /HLComment?We have found it by name;
+ \edef\@tempb{\iValue}%
+ \multidostop
+ \fi}
+ % /HLComment?We have now to get it value;
+ \checkAssociativeArray@Values(\@tempb)}
+
+ % /HLComment?Simple macro to print all the associative array;
+ /HLMacro?\def\printAssociativeArray;{%
+ \multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \iValue: \BS\texttt{FirstNames(\cachedata)}=`\AssociativeArray@Values(\iValue)'\space}}
+
+ \makeatother
+
+ \let\FirstNames\AssociativeArray
+ \let\checkFirstNames\checkAssociativeArray
+ \let\printFirstNames\printAssociativeArray
+
+ \FirstNames(Crawford)={Joan}
+ \FirstNames(Tierney)={Gene}
+ \FirstNames(Lake)={Veronika}
+
+ \printFirstNames
+
+ \checkFirstNames(Lake)
+ \verb+\FirstNames(Lake)+=`\cachedata'
+
+ \checkFirstNames(Monroe)
+ \ifemptydata
+ \verb+\FirstNames(Monroe) undefined!+
+ \else
+ \verb+\FirstNames(Monroe)+=`\cachedata'
+ \fi
+\end{Example}
+
+\makeatletter
+
+% Internally, we use two "standard" arrays to define one associative array
+\newarray\AssociativeArray@Names
+\newarray\AssociativeArray@Values
+
+\newcount\AssociativeArrayNbValues
+\AssociativeArrayNbValues=\z@
+
+\newif\ifAssociativeArray@ElementFound
+
+% To store one element
+\def\AssociativeArray(#1)=#2{%
+\expandarrayelementtrue
+\AssociativeArray@ElementFoundfalse
+\edef\@tempa{#1}%
+\Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \ifx\@tempa\cachedata
+ % This element already exist: we replace it current value
+ % \checkAssociativeArray@Values(\iValue)% debug
+ % \typeout{In #1, replace `\cachedata'\space by `#2'}% Debug
+ \AssociativeArray@Values(\iValue)={#2}%
+ \AssociativeArray@ElementFoundtrue
+ \multidostop
+ \fi}
+\ifAssociativeArray@ElementFound
+\else
+ % New element
+ \advance\AssociativeArrayNbValues\@ne
+ \AssociativeArray@Names(\AssociativeArrayNbValues)={#1}%
+ \AssociativeArray@Values(\AssociativeArrayNbValues)={#2}%
+\fi}
+
+% To get one element
+\def\checkAssociativeArray(#1){%
+\edef\@tempa{#1}%
+\edef\@tempb{999999}%
+\Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \ifx\@tempa\cachedata
+ % We have found it by name
+ \edef\@tempb{\iValue}%
+ \multidostop
+ \fi}
+% We have now to get it value
+\checkAssociativeArray@Values(\@tempb)}
+
+% Simple macro to print all the associative array
+\def\printAssociativeArray{%
+\multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \iValue: \BS\texttt{FirstNames(\cachedata)}=`\AssociativeArray@Values(\iValue)'}}
+
+\makeatother
+
+\vspace{2mm}
+ Now, we can define the macros to read a sentence, to cut it letter by letter,
+to count the occurrences of each of them, and finally to draw a summary plot of
+the results.
+
+\makeatletter % Problem with the \ifpstricks conditional if not set...
+
+\ifpstricks % If PSTricks is available
+\begin{CenterExample}
+ \makeatletter
+
+ % /HLComment?A \PerChar style macro adapted from Juergen Schlegelmilch;
+ % /HLComment?(<schlegel@Informatik.Uni-Rostock.de> - posted on c.t.t. January 27, 1998);
+ /HLMacro?\def\PerChar;#1#2{\DoPerChar#1#2\@nil}
+
+ /HLMacro?\def\DoPerChar;#1#2#3\@nil{%
+ #1#2%
+ \edef\@tempa{#3}%
+ \ifx\@tempa\empty
+ \else
+ \DoPerChar#1#3\@nil
+ \fi}
+
+ % /HLComment?The action to do for each character: we increase the counter;
+ % /HLComment?for this character by one;
+ /HLMacro?\def\ActionPerChar;#1{% /HLComment?#1=character;
+ \checkAssociativeArray(#1)%
+ \ifemptydata
+ \@tempcnta=\@ne
+ \else
+ \@tempcnta=\cachedata
+ \advance\@tempcnta\@ne
+ \fi
+ \AssociativeArray(#1)={\the\@tempcnta}}
+
+ % /HLComment?To store in an associative array the number of occurrences by characters;
+ % /HLComment?(spaces are not counted);
+ /HLMacro?\def\StatSentence;#1{% /HLComment?#1=sentence;
+ \AssociativeArrayNbValues=\z@
+ \PerChar{\ActionPerChar}{#1}}
+
+ % /HLComment?To draw a plot of the number of occurrences of the characters of a sentence;
+ /HLMacro?\def\DrawOccurrences;#1{% /HLComment?#1=sentence;
+ \StatSentence{#1}
+ %
+ \pst@cnta=\AssociativeArrayNbValues
+ \advance\pst@cnta\@ne
+ %
+ % /HLComment?To know the maximum of the numbers;
+ \pst@cntb=\z@
+ \Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Values(\iValue)%
+ \ifnum\cachedata>\pst@cntb
+ \pst@cntb=\cachedata
+ \fi}
+ \advance\pst@cntb\@ne
+ %
+ % /HLComment?The drawing itself;
+ \pspicture(-0.5,-0.5)(\pst@cnta,\pst@cntb)
+ \psaxes[axesstyle=frame,labels=y](\pst@cnta,\pst@cntb)
+ \multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \Draw@OneOccurrence{\iValue}}
+ \endpspicture}
+
+ % /HLComment?To draw the value for one occurrence;
+ /HLMacro?\def\Draw@OneOccurrence;#1{% /HLComment?#1=Letter;
+ \checkAssociativeArray@Values(#1)%
+ \psdot(#1,\cachedata)
+ \rput[B](\iValue,-0.5){\AssociativeArray@Names(#1)}}
+
+ \makeatother
+
+ \let\Names\AssociativeArray
+ \let\checkNames\checkAssociativeArray
+
+ \psset{dotstyle=o,dotsize=0.4}
+
+ \DrawOccurrences{We are Wednesday}
+\end{CenterExample}
+
+\makeatletter
+
+%% A \PerChar style macro adapted from Juergen Schlegelmilch
+%% (<schlegel@Informatik.Uni-Rostock.de> - posted on c.t.t. Jan. 27, 1998)
+\def\PerChar#1#2{\DoPerChar#1#2\@nil}
+
+\def\DoPerChar#1#2#3\@nil{%
+#1#2%
+\edef\@tempa{#3}%
+\ifx\@tempa\empty
+\else
+ \DoPerChar#1#3\@nil
+\fi}
+
+% The action to do for each character: we increase the counter
+% for this character by one
+\def\ActionPerChar#1{% #1=character
+\checkAssociativeArray(#1)%
+\ifemptydata
+ \@tempcnta=\@ne
+\else
+ \@tempcnta=\cachedata
+ \advance\@tempcnta\@ne
+\fi
+\AssociativeArray(#1)={\the\@tempcnta}}
+
+% To store in an associative array the number of occurrences by characters
+% (spaces are not counted)
+\def\StatSentence#1{% #1=sentence
+\AssociativeArrayNbValues=\z@
+\PerChar{\ActionPerChar}{#1}}
+
+% To draw a plot of the number of occurrences of the characters of a sentence
+\def\DrawOccurrences#1{%
+\StatSentence{#1}
+%
+\pst@cnta=\AssociativeArrayNbValues
+\advance\pst@cnta\@ne
+%
+% To know the maximum of the numbers
+\pst@cntb=\z@
+\Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Values(\iValue)%
+ \ifnum\cachedata>\pst@cntb
+ \pst@cntb=\cachedata
+ \fi}
+\advance\pst@cntb\@ne
+%
+% The drawing itself
+\pspicture(-0.5,-0.5)(\pst@cnta,\pst@cntb)
+ \psaxes[axesstyle=frame,labels=y](\pst@cnta,\pst@cntb)
+ \multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \Draw@OneOccurrence{\iValue}}
+\endpspicture}
+
+% To draw the value for one occurrence
+\def\Draw@OneOccurrence#1{%
+\checkAssociativeArray@Values(#1)%
+\psdot(#1,\cachedata)
+\rput[B](\iValue,-0.5){\AssociativeArray@Names(#1)}}
+
+\let\Names\AssociativeArray
+\let\checkNames\checkAssociativeArray
+
+\psset{dotstyle=o,dotsize=0.4}
+
+\makeatother
+
+\vspace{8mm} % Poor hack to force a page break...
+ We will now write another version, using another array to store indexes,
+to allow us to sort the letters found in the sentence read.
+
+\begin{CenterExample}
+ \makeatletter
+
+ % /HLComment?To get in #2 the ASCII code of the #1 character;
+ /HLMacro?\def\Character@AsciiCode;#1#2{\chardef#2=`#1\relax}
+
+ % /HLComment?A new "standard" array to store the sorted indexes;
+ \newarray\AssociativeArray@Indexes
+
+ % /HLComment?A simple macro to print the array of indexes (for debugging);
+ /HLMacro?\def\PrintIndexes;{%
+ \multido{\iIndexes=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Indexes(\iIndexes)%
+ \BS\texttt{indexes(\iIndexes)}=`\cachedata'\space}}
+
+ % /HLComment?We redefine the macro to store an element in the associative array,;
+ % /HLComment?to allow to sort it elements, using an additional array of indexes;
+ /HLMacro?\def\AssociativeArray;(#1)=#2{%
+ \expandarrayelementtrue
+ \AssociativeArray@ElementFoundfalse
+ \edef\@tempa{#1}%
+ \edef\@tempb{#2}%
+ \Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \ifx\@tempa\cachedata
+ % /HLComment?This element already exist: we replace it current value;
+ % /HLComment?\checkAssociativeArray@Values(\iValue)% Debug;
+ % /HLComment?\typeout{In #1, replace `\cachedata'\space by `#2'}% Debug;
+ \AssociativeArray@Values(\iValue)={\@tempb}%
+ \AssociativeArray@ElementFoundtrue
+ \multidostop
+ \fi}
+ \ifAssociativeArray@ElementFound
+ \else
+ % /HLComment?New element: we must insert it at it sorted position;
+ \@tempcnta=\@ne
+ \expandafter\Character@AsciiCode\@tempa\@tempx
+ \Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \expandafter\Character@AsciiCode\cachedata\@tempy
+ \ifnum\@tempx<\@tempy
+ % /HLComment?The new element must be before this one: we will exchange their values;
+ \checkAssociativeArray@Indexes(\iValue)%
+ \@tempcntb=\cachedata
+ \advance\@tempcntb\@ne
+ \AssociativeArray@Indexes(\iValue)={\the\@tempcntb}%
+ \else
+ \advance\@tempcnta\@ne
+ \fi}
+ %
+ \advance\AssociativeArrayNbValues\@ne
+ \AssociativeArray@Names(\AssociativeArrayNbValues)={\@tempa}%
+ \AssociativeArray@Values(\AssociativeArrayNbValues)={\@tempb}%
+ \AssociativeArray@Indexes(\AssociativeArrayNbValues)={\the\@tempcnta}%
+ \fi}
+
+ % /HLComment?We change the way we draw each number of occurrences;
+ /HLMacro?\def\Draw@OneOccurrence;#1{%
+ \checkAssociativeArray@Indexes(#1)%
+ \pst@cnta=\cachedata
+ \checkAssociativeArray@Values(#1)%
+ \psdot(\the\pst@cnta,\cachedata)
+ \rput[B](\the\pst@cnta,-0.5){\AssociativeArray@Names(#1)}}
+
+ \makeatother
+
+ \DrawOccurrences{We are Wednesday}
+
+ \PrintIndexes
+\end{CenterExample}
+
+\makeatletter
+
+% To get in #2 the ASCII code of the #1 character
+\def\Character@AsciiCode#1#2{\chardef#2=`#1\relax}%
+
+% A new "standard" array to store the sorted indexes
+\newarray\AssociativeArray@Indexes
+
+% We redefine the macro to store an element in the associative array,
+% to allow to sort it elements, using an additional array of indexes
+\def\AssociativeArray(#1)=#2{%
+\expandarrayelementtrue
+\AssociativeArray@ElementFoundfalse
+\edef\@tempa{#1}%
+\edef\@tempb{#2}%
+\Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \ifx\@tempa\cachedata
+ % This element already exist: we replace it current value
+ % \checkAssociativeArray@Values(\iValue)% Debug
+ % \typeout{In #1, replace `\cachedata'\space by `#2'}% Debug
+ \AssociativeArray@Values(\iValue)={\@tempb}%
+ \AssociativeArray@ElementFoundtrue
+ \multidostop
+ \fi}
+\ifAssociativeArray@ElementFound
+\else
+ % New element: we must insert it at it sorted position
+ \@tempcnta=\@ne
+ \expandafter\Character@AsciiCode\@tempa\@tempx
+ \Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \expandafter\Character@AsciiCode\cachedata\@tempy
+ \ifnum\@tempx<\@tempy
+ % The new element must be before this one: we will exchange their values
+ \checkAssociativeArray@Indexes(\iValue)%
+ \@tempcntb=\cachedata
+ \advance\@tempcntb\@ne
+ \AssociativeArray@Indexes(\iValue)={\the\@tempcntb}%
+ \else
+ \advance\@tempcnta\@ne
+ \fi}
+ %
+ \advance\AssociativeArrayNbValues\@ne
+ \AssociativeArray@Names(\AssociativeArrayNbValues)={\@tempa}%
+ \AssociativeArray@Values(\AssociativeArrayNbValues)={\@tempb}%
+ \AssociativeArray@Indexes(\AssociativeArrayNbValues)={\the\@tempcnta}%
+\fi}
+
+% We change the way we draw each number of occurrences
+\def\Draw@OneOccurrence#1{%
+\checkAssociativeArray@Indexes(#1)%
+\pst@cnta=\cachedata
+\checkAssociativeArray@Values(#1)%
+\psdot(\the\pst@cnta,\cachedata)
+\rput[B](\the\pst@cnta,-0.5){\AssociativeArray@Names(#1)}}
+
+\makeatother
+
+\begin{CenterExample}
+ \DrawOccurrences{Tuesday 8 February}
+\end{CenterExample}
+
+\noindent Now, we can easily redefine the internal macro which plot each
+occurrence, to obtain various kinds of graphics:
+
+\begin{CenterExample}
+ \makeatletter
+
+ /HLMacro?\def\Draw@OneOccurrence;#1{%
+ \checkAssociativeArray@Indexes(#1)%
+ \pst@cnta=\cachedata
+ \checkAssociativeArray@Values(#1)
+ \psline[linestyle=dotted](\the\pst@cnta,0)(\the\pst@cnta,\cachedata)
+ \psdot(\the\pst@cnta,\cachedata)
+ \rput[B](\the\pst@cnta,-0.5){\AssociativeArray@Names(#1)}}
+
+ \makeatother
+
+ \psset{xunit=0.5,dotstyle=*,dotsize=0.3}
+ \DrawOccurrences{I do not believe that it can be correct}
+\end{CenterExample}
+
+\begin{CenterExample}
+ \makeatletter
+
+ \SpecialCoor
+
+ /HLMacro?\def\Draw@OneOccurrence;#1{%
+ \checkAssociativeArray@Indexes(#1)%
+ \pst@cnta=\cachedata
+ \checkAssociativeArray@Values(#1)%
+ \pspolygon*[linecolor=red](! \the\pst@cnta\space 0.3 sub 0)
+ (! \the\pst@cnta\space 0.3 sub \cachedata)
+ (! \the\pst@cnta\space 0.3 add \cachedata)
+ (! \the\pst@cnta\space 0.3 add 0)
+ \rput[B](\the\pst@cnta,-0.5){\AssociativeArray@Names(#1)}}
+
+ \makeatother
+
+ \psset{xunit=0.5,ticks=y}
+ \DrawOccurrences{I don't know a better solution than this one}
+\end{CenterExample}
+\else
+ \PSTricksExampleNotShown
+\fi % End \pstrickstrue
+
+\section{Thanks}
+
+ I would like to thank Rolf Niepraschk \verb+<niepraschk@ptb.de>+ to have
+carefully read a preliminary version of this document and to have sent me
+several good advices to clarify and improve some points.
+
+\begin{thebibliography}{9}
+ \bibitem{SVB93} Stephan von \textsc{Bechtolsheim}, \emph{\TeX{} in
+ Practice}, four volumes, Springer-Verlag, New York, 1993 (see also
+ \url{CTAN: macros/tip/arraymac.tip}).
+ \bibitem{REPEAT} \RepeatPackage, by Victor \textsc{Eijkhout}, University of
+ Illinois, Urbana-Champaign, USA, \url{CTAN: macros/generic/eijkhout/repeat}
+ \bibitem{EG98} Philippe \textsc{Esperet} and Denis \textsc{Girou},
+ \emph{Coloriage du pavage dit de Truchet}, Cahiers GUTenberg, Number~31,
+ December 98, pages 5-18, in french (see
+ \url{http://www.gutenberg.eu.org/pub/GUTenberg/publicationsPS/31-girou.ps.gz}).
+ \bibitem{ALDRATEX} \AlDraTeXPackage, by Eitan M. \textsc{Gurari}, Ohio State
+ University, Columbus, USA, \url{CTAN: graphics/dratex} (see also
+ \url{http://www.cis.ohio-state.edu/~gurari/systems.html}).
+ \bibitem{Gur94} Eitan M. \textsc{Gurari}, \emph{\TeX{} and \LaTeX: Drawing
+ and Literate Programming}, McGraw-Hill, New-York, 1994.
+ \bibitem{METAPOST} \MetaPostPackage, by John D. \textsc{Hobby}, AT\&T Bell
+ Laboratories, USA, \url{CTAN: graphics/metapost} (see also
+ \url{http://cm.bell-labs.com/who/hobby/MetaPost.html}).
+ \bibitem{FORMLETT} \FormLettPackage, by Zhuhan \textsc{Jiang}, University of
+ New England, Armidale, Australia, \url{CTAN: macros/generic/formlett.sty} (see
+ also \url{http://maths.une.edu.au/~zhuhan/util.html#computer}).
+ \bibitem{MULTIDO} \MultiDoPackage, by Timothy van \textsc{Zandt}, INSEAD,
+ Fontainebleau, France, \url{CTAN: macros/generic/multido}
+ \bibitem{PSTRICKS} \PSTricksPackage, by Timothy van \textsc{Zandt}, INSEAD,
+ Fontainebleau, France, \url{CTAN: graphics/pstricks} (see also
+ \url{http://www.tug.org/applications/PSTricks}).
+\end{thebibliography}
+
+\end{document}
diff --git a/macros/generic/arrayjobx/arrayjobx.pdf b/macros/generic/arrayjobx/arrayjobx.pdf
new file mode 100644
index 0000000000..25699278ee
--- /dev/null
+++ b/macros/generic/arrayjobx/arrayjobx.pdf
Binary files differ
diff --git a/macros/generic/arrayjobx/arrayjobx.sty b/macros/generic/arrayjobx/arrayjobx.sty
new file mode 100644
index 0000000000..fb533f625a
--- /dev/null
+++ b/macros/generic/arrayjobx/arrayjobx.sty
@@ -0,0 +1,192 @@
+% ARRAY STRUCTURE - arrayjobx.sty - Version 1.04 - 05/03/10
+%
+% By Zhuhan Jiang (01/05/95), extracted from formlett.sty
+% (see CTAN/macros/generic/formlett.sty from line 344 to line 483)
+%
+% This program can be redistributed and/or modified under the terms
+% of the LaTeX Project Public License distributed from CTAN archives
+% in directory macros/latex/base/lppl.txt
+%
+% * 01/05/95 - Version 1.00
+% + Original version
+% * 12/21/99 - Version 1.01
+% + Spurious blanks removed in \read@array and \get@max@count
+% (reported by Antonio Leitao <aml@gia.ist.utl.pt>
+% and Denis Girou <Denis.Girou@idris.fr>)
+% * 04/05/00 - Version 1.02
+% + Add the \ifexpandarrayelement macro to allow to evaluate
+% or not the content to put as an element of the array
+% (from Denis Girou <Denis.Girou@idris.fr>)
+% + Put this package under the terms of the LaTeX Project
+% Public License
+% * 05/03/00 - Version 1.03
+% + Add a \ProvidesPackage macro when LaTeX is used
+% (according to the example given by Bernd Raichle
+% <raichle@Informatik.Uni-Stuttgart.DE>)
+% * 05/03/10 - Version 1.04
+% + Change the name of the macro \array to \arrayx
+% to avoid conflict with macros in the amsmath package.
+% Change suggested by Michael Sharpe (msharpe at ucsd.edu)
+%
+%
+% \newarray\ARRAYNAME
+% \delarray\ARRAYNAME
+%
+% \ARRAYNAME(A1,..,An)={T}
+% \readarray{ARRAYNAME}{ B1 & B2 & ... & Bm }
+% \dataheight
+%
+% \data(A1,...,An)=\data( A1 + (A2-1)*\dataheight +
+% ... + (An-1)*\dataheight^{n-1} )
+% if \normalindextrue
+% =\data( An + (An-1 -1)*\dataheight +
+% ... + (A1-1)*\dataheight^{n-1} )
+% if \normalindexfalse
+%
+% \checkARRAYNAME(A1,..,An)
+% \ifemptydata valid when \checkARRAYNAME is just executed
+% \cachedata: keeps the data of \ARRAYNAME(m)
+% when \checkARRAYNAME(m) is executed
+%
+% OTHERS:
+% save to array: \arrayx{n}(m)={T}
+% get from array: \arrayx{n}(m)
+% clear element: \clrarray{n}(m)
+% test element: \testarray{n}(m)
+% macro save to \temp@macro
+%
+%
+% e.g.
+%
+% \newarray\Table
+% \readarray{Table}{one&two& \unknownmacro && &six}
+% \Table(7)={seven}
+% \dataheight=0 % or 1 or < 0
+% \Table(7) = \Table(2,6,1) % 7=1+(2-1)+(6-1)+(1-1)
+% \normalindexfalse
+% \dataheight=3
+% \Table(7) = \Table(1,7) = \Table(3,1)
+% \normalindextrue
+% \Table(7) = \Table(7,1) = \Table(1,3)
+%
+% \checkTable(4) \ifemptydata (4)=empty \fi
+% \checkTable(5) \ifemptydata\else (5)=nonempty \fi
+% \ifx\cachedata\space ={\tt <space>}\fi
+% \checkTable(1000) \ifemptydata (1000)=empty \fi
+%
+% \delarray\Table
+%
+%
+\begingroup\expandafter\expandafter\expandafter\endgroup
+\expandafter\ifx\csname ProvidesPackage\endcsname\relax%
+\else
+ \ProvidesPackage{arrayjobx}[2010/05/03 v1.04 Array management]
+\fi
+%
+\xdef\EntryArrayJob{\the\catcode`\@}\catcode`\@=11\relax
+\newif\ifemptydata \newcount\dataheight
+\newif\ifnormalindex \normalindexfalse
+%
+\newcount\array@width \newcount\index@count \newcount\index@total
+\newif\ifone@VEC \newif\if@rev@index
+\newtoks\temp@toks \newcount\temp@count
+\newcount\temp@@count \newcount\temp@@@count
+%
+\newif\ifexpandarrayelement
+%
+\long\def\assign@VEC#1(#2)=#3{\temp@count=#2 \relax
+\get@max@count{total@#1}\temp@count
+\ifexpandarrayelement
+ \expandafter\xdef\csname#1#2\string~\endcsname{#3}%
+\else
+ \expandafter\gdef\csname#1#2\string~\endcsname{#3}%
+\fi}
+\def\get@VEC#1(#2){\csname#1#2\string~\endcsname}
+\def\clrarray#1(#2){%
+ \global\expandafter\let\csname#1#2\string~\endcsname=\undefined@}
+%
+\def\testarray#1(#2){%
+ \expandafter\let\expandafter\temp@macro\csname#1#2\string~\endcsname
+ \ifx\temp@macro\relax \def\temp@macro{}\fi}%
+%
+\def\arrayx#1(#2){\def\check@VEC{%
+ \ifx=\next@VEC \def\full@VEC####1{\assign@VEC#1(#2)####1}%
+ \else \def\full@VEC{\get@VEC#1(#2)}\fi \full@VEC}%check@VEC
+\futurelet\next@VEC\check@VEC}
+%
+\def\get@index(#1)#2\safty@mark{\one@VEC#2,\safty@mark
+ \def\next@@VEC{#1}\ifx\next@@VEC\empty\def\next@@VEC{\array@width}\fi
+ \if@rev@index
+ {\temp@count=1 \advance\index@count1 \relax
+ \ifnum\index@count<\index@total
+ \loop \multiply\temp@count \next@@VEC
+ \advance\index@count-1 \relax
+ \ifnum\index@count>0 \repeat
+ \fi \global\temp@@count\temp@count }%
+ \else \multiply\temp@@count \next@@VEC \fi
+ \ifnum\temp@@count=0 \temp@@count=1 \relax \fi
+ \advance\temp@count-1 \ifnum\temp@count<0 \temp@count=0 \fi
+ \multiply\temp@count \temp@@count
+ \advance\temp@@@count by \temp@count \advance\index@count1
+ \ifone@VEC
+ \def\next@@VEC{\index@total=\index@count \advance\temp@@@count1 }%
+ \else \one@VEC#2\safty@mark \edef\next@@VEC{\noexpand\get@index(#1)%
+ \the\temp@toks\noexpand\safty@mark}%
+ \fi \next@@VEC}%
+%
+\def\one@VEC#1,#2\safty@mark{\def\temp@macro{#2}\temp@toks={#2}%
+ \ifx\temp@macro\empty \one@VECtrue \else \one@VECfalse \fi
+ \temp@count=#1 \relax }%
+%
+\def\get@all@index(#1)#2\safty@mark{%
+ \temp@@@count=0 \temp@@count=0 \index@count=0 \@rev@indexfalse
+ \get@index(#1)#2\safty@mark
+ \ifnormalindex\else
+ \temp@@@count=0 \temp@@count=0 \index@count=0 \@rev@indextrue
+ \get@index(#1)#2\safty@mark \fi }%
+%
+\def\read@array[#1]#2#3{\temp@count=1
+ \def\one@item##1#1##2\safty@mark{\def\temp@macro{##2}\temp@toks={##2}%
+ \ifx\temp@macro\empty\else
+ \def\temp@macro{\one@item##2\safty@mark}\fi
+ {\temp@toks={##1}\def\temp@@macro{\arrayx{#2}(\the\temp@count)=}%
+ \expandafter\temp@@macro\expandafter{\the\temp@toks}}%
+ \expandafter\edef\csname total@#2\endcsname{\the\temp@count}%
+ \advance\temp@count1\temp@macro}%
+ \one@item#3#1\safty@mark}%
+%
+\def\strip@esc#1{\temp@count=\escapechar \escapechar=-1 %
+ \temp@toks=\expandafter{\string#1}\escapechar\temp@count}
+\def\get@max@count#1#2{\edef\temp@macro{\csname #1\endcsname}%
+ \ifnum\temp@macro<#2\expandafter\xdef\csname #1\endcsname{\the#2}\fi}%
+%
+\def\newarray#1{\strip@esc{#1}%
+ \expandafter\gdef\csname total@\the\temp@toks\endcsname{0}%
+ \expandafter\edef\csname\the\temp@toks\endcsname(##1)%
+ {\noexpand\get@all@index(\noexpand\dataheight)##1\noexpand\safty@mark
+% \noexpand\get@max@count{total@\the\temp@toks}\noexpand\temp@@@count
+ \noexpand\arrayx{\the\temp@toks}(\noexpand\the\noexpand\temp@@@count)}%
+ \expandafter\edef\csname check\the\temp@toks\endcsname(##1)%
+ {\noexpand\get@all@index(\noexpand\dataheight)##1\noexpand\safty@mark
+ \noexpand\testarray{\the\temp@toks}(\noexpand\the
+ \noexpand\temp@@@count)\noexpand\let\noexpand\cachedata
+ \noexpand\temp@macro\noexpand\ifx\noexpand\temp@macro\noexpand\empty
+ \noexpand\emptydatatrue\noexpand\else\noexpand\emptydatafalse
+ \noexpand\fi}}%
+%
+\def\delarray#1{\strip@esc{#1}% delete array globally
+ \temp@count=0 \temp@@count=\csname total@\the\temp@toks\endcsname
+ \loop \expandafter\global\expandafter\let
+ \csname\the\temp@toks\string~\endcsname\undefined@
+ \advance\temp@count1 %
+ \ifnum\temp@count<\temp@@count \repeat % global loop for less memory
+ \global\expandafter\let\csname total@\the\temp@toks\endcsname\undefined@
+ \global\expandafter\let\csname \the\temp@toks\endcsname\undefined@
+ \global\expandafter\let\csname check\the\temp@toks\endcsname\undefined@ }%
+%
+\def\readarray#1#2{\read@array[&]{#1}{#2}}%
+%
+\catcode`\@=\EntryArrayJob\relax
+\endinput
+%
+% END OF MACROS
diff --git a/macros/generic/arrayjobx/arrayjobx.tex b/macros/generic/arrayjobx/arrayjobx.tex
new file mode 100644
index 0000000000..0dbd380f55
--- /dev/null
+++ b/macros/generic/arrayjobx/arrayjobx.tex
@@ -0,0 +1,2096 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -*- Mode: Latex -*- %%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% arrayjobx.tex --- Documentation of the `arrayjobx' package from Zhuhan Jiang
+%%
+%% Author : Denis GIROU (CNRS/IDRIS - France) <Denis.Girou@idris.fr>
+%% Created the : Fri Jan 7 21:13:20 2000
+%% Last mod. by : Michael Sharpe (UCSD - USA) <msharpe@ucsd.edu>
+%% Last mod. the : Mon May 3 11:18:300 2010
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\documentclass{article}
+
+\usepackage{arrayjobx} % Arrays management
+\usepackage{fancyvrb} % Fancy verbatims
+\usepackage[width=18cm]{geometry} % Page layout
+\usepackage{graphics} % Graphics LaTeX standard package
+\usepackage{ifthen} % Convenient conditionals in LaTeX
+\usepackage{mflogo} % For the MetaFont and MetaPost logos
+\usepackage{multido} % General loop macro
+\usepackage{url} % URLs convenient typesetting
+
+% For PSTricks examples
+\newif\ifpstricks
+\IfFileExists{pstricks.sty}{%
+\pstrickstrue
+%\usepackage{pstcol} % PSTricks package with `color' interface
+\usepackage{pst-node} % PSTricks nodes package
+\usepackage{pst-plot} % PSTricks plots package
+\usepackage{pst-grad} % PSTricks gradients package
+%\usepackage{pst-key} % PSTricks interface to the `keyval' package
+}{%
+\usepackage{color}
+} % Color LaTeX standard package
+
+% Definition of new colors
+\definecolor{Khaki} {rgb}{0.94,0.90,0.55}
+\definecolor{LemonChiffon}{rgb}{1.,0.98,0.8}
+
+% A unique string for TeX and LaTeX
+\newcommand{\AllTeX}{%
+{\rm(L\kern-.36em\raise.3ex\hbox{\sc a}\kern-.15em)%
+T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}}
+
+% Package names
+\newcommand{\AlDraTeXPackage}{\textsf{(Al)Dra\TeX}}
+\newcommand{\ArrayJobPackage}{`\textsf{arrayjobx}'}
+\newcommand{\FormLettPackage}{`\textsf{formlett}'}
+\newcommand{\IfThenPackage}{`\textsf{ifthen}'}
+\newcommand{\MetaFontPackage}{\MF}
+\newcommand{\MetaPostPackage}{\MP}
+\newcommand{\MultiDoPackage}{`\textsf{multido}'}
+\newcommand{\PSTricksPackage}{\textsf{PSTricks}}
+\newcommand{\RepeatPackage}{`\textsf{repeat}'}
+
+% Aligned labels in a description environment
+\newenvironment{Description}[1]{%
+\begin{list}{nothing}{\setlength{\leftmargin}{#1}
+\setlength{\labelwidth}{\leftmargin}\setlength{\labelsep}{1mm}}}
+{\end{list}}
+
+% If PSTricks is not available
+\newcommand{\PSTricksExampleNotShown}{%
+\vspace{2mm}
+\centerline{\fbox{\textbf{Example not shown here because PSTricks is not
+ available on this platform.}}}}
+
+% Character to define verbatim strings, with escape characters /?; (from `fancyvrb')
+\DefineShortVerb[commandchars=/?;]{\!}
+
+\VerbatimFootnotes % Allow verbatim material in footnotes (from `fancyvrb')
+
+% Some advices from Rolf Niepraschk
+\newcommand{\BS}{\texttt{\symbol{`\\}}}
+\newcommand{\Macro}[1]{\texttt{\BS#1}}
+\newcommand{\Variable}[1]{\textnormal{\textit{\(\langle\)#1\,\(\rangle\)}}}
+\newcommand{\Parameter}[1]{\texttt{\symbol{`\{}#1\symbol{`\}}}}
+
+% To format TeX macro strings
+\newcommand{\FormatTeXMacro}[1]{\Macro{#1}\hfill :}
+
+\makeatletter
+
+% Example environments
+% (do not use in them the /?; characters, that we will be used as escape characters!)
+
+% For highlighting some verbatim sequences (array names, macro names and comments)
+\def\HLReverse#1{{%
+\setlength{\fboxsep}{1pt}%
+\colorbox{black}{\textcolor{white}{\textbf{#1}}}}}
+\def\HLMacro#1{\BS{}def\HLMacro@i#1\@nil}
+\def\HLMacro@i#1def#2\@nil{{%
+\setlength{\fboxsep}{1pt}%
+\colorbox{black}{\textcolor{white}{\textbf{#2}}}}}
+\def\HLComment#1{\textit{#1}}
+
+\def\Example{\FV@Environment{}{Example}}
+\def\endExample{%
+\end{VerbatimOut}
+\Below@Example{\input{\jobname.tmp}}
+\endgroup}
+
+\def\CenterExample{\FV@Environment{}{Example}}
+\def\endCenterExample{%
+\end{VerbatimOut}%
+\begin{center}
+\Below@Example{\input{\jobname.tmp}}
+\end{center}
+\endgroup}
+
+\def\SideBySideExample{\FV@Environment{}{Example}}
+\def\endSideBySideExample{%
+\end{VerbatimOut}%
+\SideBySide@Example{\input{\jobname.tmp}}
+\endgroup}
+
+\def\FVB@Example{%
+\begingroup
+\FV@UseKeyValues
+\parindent=0pt
+\multiply\topsep by 2
+\VerbatimEnvironment
+\begin{VerbatimOut}[codes={\catcode`\Z=12}]{\jobname.tmp}}
+
+\def\Below@Example#1{%
+\VerbatimInput[gobble=0,commentchar=Z,commandchars=/?;,numbersep=3pt,
+ frame=single,numbers=left]%
+ {\jobname.tmp}
+\catcode`\Z=9\relax%
+% We suppress the effect of the highlighting macros
+\catcode`/=0\relax%
+\catcode`?=1\relax%
+\catcode`;=2\relax%
+\def\HLReverse##1{##1}%
+\def\HLMacro##1{##1}%
+\def\HLComment##1{##1}%
+#1\par}
+
+\def\SideBySide@Example#1{%
+\@tempdimb=\FV@XRightMargin
+\advance\@tempdimb -5mm
+\begin{minipage}[c]{\@tempdimb}
+ \fvset{xrightmargin=0pt}
+ \catcode`\Z=9\relax%
+ % We suppress the effect of the highlighting macros
+ \catcode`/=0\relax%
+ \catcode`?=1\relax%
+ \catcode`;=2\relax%
+ \def\HLReverse##1{##1}%
+ \def\HLMacro##1{##1}%
+ \def\HLComment##1{##1}%
+ #1
+\end{minipage}%
+\@tempdimb=\textwidth
+\advance\@tempdimb -\FV@XRightMargin
+\advance\@tempdimb 5mm
+\begin{minipage}[c]{\@tempdimb}
+ \VerbatimInput[gobble=0,commentchar=Z,commandchars=/?;,
+ numbersep=3pt,frame=single,numbers=left,
+ xleftmargin=5mm,xrightmargin=0pt]{\jobname.tmp}
+\end{minipage}}
+
+\makeatother
+
+% Source codes must be indented by 2 spaces
+\fvset{gobble=2,frame=single,numbers=left,numbersep=1mm}
+
+\begin{document}
+
+\title{The \ArrayJobPackage{} package\\Management of arrays in \AllTeX}
+\author{Zhuhan Jiang\\School of Computing and Mathematics\\
+ University of Western Sydney\\Sydney\\Australia\\
+ {\footnotesize email: zhuhan@scm.uws.edu.au}\\[5mm]
+ {\footnotesize (Documentation: Denis Girou%
+ \footnote{All errors and misunderstandings are mine.}
+ \hspace{1mm}(CNRS/IDRIS -- France) --
+ Denis.Girou@idris.fr)}}
+\date{Version 1.04\\May 3, 2010\\
+ {\small Documentation revised May 31, 2000, edited lightly May 3, 2010 by Michael Sharpe}}
+
+\maketitle
+
+\begin{abstract}
+ This package provides array data structures in \AllTeX, in the meaning of
+the classical procedural programming languages like Fortran, Ada or C, and
+macros to manipulate them. Arrays can be mono or bi-dimensional.
+
+ This is useful for applications which require high level programming
+techniques, like algorithmic graphics programmed in \TeX. This version no longer conflicts with some macros in the {\tt amsmath} package. It should be used for all new work.
+\end{abstract}
+
+\tableofcontents
+
+\section{Introduction}
+
+ One of the big advantages of the \AllTeX{} system over common interactive
+software for text processing is that it offer, also, a programming language,
+which give, to people who have some knowledge in the algorithmic and
+programming fields, an exceptional flexibility and power.
+
+ Nevertheless, \TeX{} is a rather specific programming language, based on
+macro expansion, which implements a lot of unusual constructs but lacks some that are very familiar in the classical procedural languages, as
+\emph{arrays} to store and retrieve arbitrary pieces of data, stored in a
+structured way. The main reason why they were not integrated in \TeX{} was
+perhaps that arrays did not seem very useful in a language focussed on text processing (but
+\MetaFontPackage{}, for instance, does has them). Nevertheless, one of the few
+applications where this is straightforward to use them is to program a mailing
+system, where nearly the same information is to be formatted several times,
+depending of values which can be simply retrieved from an array of data. This
+was the goal of the \FormLettPackage{} package \cite{FORMLETT}, written in
+1993-1995 by Zhuhan Jiang for dealing with mass letters, invoices and similar
+tasks of some duplicative nature. It implemented a small but powerful set of
+macros to manage arrays, which have been extracted to form the present
+\ArrayJobPackage{} package. The arrays can be mono or bi-dimensional%
+\footnote{You can use more than two dimensions, but not in the meaning of the
+classical programming languages (see page \pageref{par:DataHeight})}
+and they are dynamically allocated (so we do not have to declare their
+dimension statically.)%
+\footnote{Stephan von Bechtolsheim \cite[Volume \textsc{III}, paragraph 20.3,
+page 136]{SVB93} also demonstrated such macros for array management in the
+third volume of his huge book, but it was limited to mono-dimensional
+arrays.}.
+
+ Array structures are, at the opposite of text management, often very useful
+in graphic programming. This is why the \AlDraTeXPackage{} package from Eitan
+Gurari \cite{ALDRATEX} (see also \cite{Gur94}) integrate such functionality
+(but which is bundled inside this package and could not be extracted easily
+from it), and this is also the case for the \MetaPostPackage{} package
+\cite{METAPOST} (but this one do not use \TeX{} as programming language)%
+\footnote{Another required feature, used in conjunction with the managements
+of arrays, is a generic loop mechanism. \TeX{} offer the \Macro{loop} macro
+and \LaTeX{} the \Macro{whiledo} macro of the \IfThenPackage{} package (and
+also the internal \Macro{@for}, \Macro{@whilenum}, etc. macros), but a more
+high-level structure is to be preferred, as the ones defined too in the
+\AlDraTeXPackage{} or \MetaPostPackage{} packages. We will use in our examples
+the \MultiDoPackage{} package \cite{MULTIDO}, also written by Timothy van
+Zandt, but others are available, like the \RepeatPackage{} package written by
+Victor Eijkhout \cite{REPEAT}.}. This fact explain why most of our examples in
+this documentation will concern the area of \emph{graphic programming} (here
+using the \PSTricksPackage{} package from Timothy van Zandt \cite{PSTRICKS}).
+
+\section{Command reference}
+
+\begin{Description}{4cm}
+ \item[\FormatTeXMacro{newarray}] Define a new array.
+
+ Syntax: !\newarray/Macro?/Variable?ArrayName;;!
+
+ Example: !\newarray\Values!
+
+ \item[\FormatTeXMacro{delarray}] Delete an array.
+
+ Syntax: !\delarray/Macro?/Variable?ArrayName;;!
+
+ Example: !\delarray\Values!
+
+ Remarks:
+ \begin{enumerate}
+ \item obviously, elements of a deleted array could not be accessed
+ later,
+ \item take care that the elements of a deleted array are not
+ themselves deleted.\newline
+ So, \verb+\delarray\Data \newarray\Data \Data(I)+ can produce
+ strange behavior. Just avoid reusing deleted arrays.
+ \end{enumerate}
+
+ \item[\FormatTeXMacro{ArrayName}] Store or get the content of the array
+ element specified by the index/indices. In the last case, the content is
+ inserted at the current point.
+
+ Syntax: !/Macro?/Variable?ArrayName;;(I)=/Parameter?/Variable?Content;;! or more
+ generally\newline
+ \hspace*{1.3cm}!/Macro?/Variable?ArrayName;;(I1,...,In)=/Parameter?/Variable?Content;;!
+ to store a value
+
+ \hspace{1.3cm}!/Macro?/Variable?ArrayName;;(I)! or more generally
+ !/Macro?/Variable?ArrayName;;(I1,...,In)! to retrieve a value
+
+ Examples: !\Data(6)={Paul Adams}!
+
+ \hspace{1.75cm}!\Values(19)!
+
+ \item[\FormatTeXMacro{readarray}] Store consecutive values in an array,
+ starting from the indice one.
+
+ Syntax: !\readarray/Parameter?/Variable?ArrayName;;=/Parameter?/Variable?Content1;&...&/Variable?ContentM;;!
+
+ Example: !\readarray{Actors}{Louise Brooks&Marlene Dietrich&Clark Gable}!
+
+ Remarks:
+ \begin{enumerate}
+ \item the values must be separated by the \textbf{\&} character,
+ \item take care that the trailing spaces are significant, so the
+ previous definition is different from the following one:
+
+ !\readarray{Actors}{Louise Brooks & Marlene Dietrich & Clark Gable}!
+ \item you can use \AllTeX{} macros inside the values.
+ \end{enumerate}
+\end{Description}
+
+\begin{SideBySideExample}[xrightmargin=6cm]
+ \newarray\Values
+ \readarray{/HLReverse?Values;}{A&B&C&D}
+ \verb+\Values(3)+ = `\Values(3)'
+ \newarray\Actors
+ \readarray{/HLReverse?Actors;}{Louise Brooks&Marlene Dietrich&Clark Gable}
+ Z\par
+ \verb+\Actors(2)+ = `\Actors(2)'
+ \readarray{/HLReverse?Actors;}{%
+ Louise Brooks & Marlene Dietrich & Clark Gable}
+ Z\par
+ \verb+\Actors(2)+ = `\Actors(2)'
+ \Actors(4)={\textit{\underline{Ida Lupino}}}
+ Z\par
+ \verb+\Actors(4)+ = `\Actors(4)'
+\end{SideBySideExample}
+
+\vspace{3mm}
+\noindent If you really need to trim the unnecessary left and right spaces, you must
+apply a special action, like this one:
+
+\begin{Example}
+ \def\BS{\texttt{\symbol{`\\}}}
+
+ \newarray\Strings
+ \readarray{/HLReverse?Strings;}{a& b&c c & d dd ddd }
+
+ \multido{\iString=1+1}{4}{%
+ \checkStrings(\iString)%
+ \BS\texttt{Strings(\iString)}=`\cachedata'\qquad}
+
+ \makeatletter
+
+ % /HLComment?A \TrimSpaces macro adapted from Michael J. Downes <epsmjd@ams.org>;
+ % /HLComment?(posted on c.t.t. June 19, 1998);
+ % /HLComment?\number`\x reads past one following space (expanding as it goes);
+ \long\def\TrimSpaces#1{\expandafter\TrimSpaces@i\number`\^^00#1| |}
+ % /HLComment?Remove the "0" produced by \number`\^^00, and " |" at the end.;
+ \long\def\TrimSpaces@i 0#1 |{\TrimSpaces@ii\empty#1|}
+ % /HLComment?" |" was removed by \TrimSpaces@i, now remove a trailing "||" or "| |";
+ \long\def\TrimSpaces@ii #1|#2|{#1}
+
+ \makeatother
+
+ \multido{\iString=1+1}{4}{%
+ \checkStrings(\iString)%
+ \BS\texttt{Strings(\iString)}=`\TrimSpaces{\cachedata}'\qquad}
+\end{Example}
+
+\begin{Description}{4cm}
+ \item[\FormatTeXMacro{check}] Get the content of the array element specified
+ by the indice(s) and store the result in the macro !\cachedata!
+
+ Syntax: !\check/Variable?ArrayName;(I)! or more generally
+ !\check/Variable?ArrayName;(I1,..,In)!
+
+ Example: !\checkActors(2)!
+ \item[\FormatTeXMacro{cachedata}] Macro where the content is stored after
+ a !\check! request.
+ \item[\FormatTeXMacro{ifemptydata}] True if the last \Macro{check} request
+ has given an empty result.
+\end{Description}
+
+\newarray\Values
+\readarray{Values}{A&B&C&D}
+
+\newarray\Actors
+\newarray\Dates
+\newarray\Sexes
+\readarray{Actors}{Louise Brooks&%
+ Marlene Dietrich&%
+ Clark Gable}
+\readarray{Dates}{1906--1985&%
+ 1902--1992&%
+ 1901--1960}
+\readarray{Sexes}{2&2&1}
+
+\begin{SideBySideExample}[xrightmargin=6cm]
+ % /HLComment?Plain TeX usage;
+ \checkValues(2)%
+ \verb+\Values(2)+ = `\cachedata'
+ Z\par
+ \checkActors(3)%
+ \verb+\Actors(3)+ = `\cachedata'
+ Z\par
+ \checkActors(5)%
+ \ifemptydata
+ \verb+\Actors(5)+ not defined.
+ \fi
+ Z\par
+ % /HLComment?LaTeX usage;
+ \newcommand{\IsEmptyElement}[2]{%
+ \ifthenelse{\boolean{emptydata}}{#1}{#2}}
+ \checkActors(3)%
+ \verb+\Actors(3)+ = \IsEmptyElement{not defined}{`\cachedata'}
+ Z\par
+ \checkActors(5)%
+ \verb+\Actors(5)+ \IsEmptyElement{not defined}{`\cachedata'}
+\end{SideBySideExample}
+
+\begin{Description}{4cm}
+ \item[\FormatTeXMacro{ifnormalindex}] See below (Default: !\normalindexfalse!).
+
+ \item[\FormatTeXMacro{dataheight}\label{par:DataHeight}] Counter containing
+ the number of elements in the first dimension, if arrays are bi-dimensional.
+
+ Syntax: !\dataheight=/Variable?Number;!
+
+ Remarks:
+ \begin{enumerate}
+ \item arrays are monodimensional when !\dataheight!~$\leq~1$,
+ \item if !\normalindexfalse! (which is the default value), we have:
+ $$\hspace{-3cm}\Macro{\Variable{ArrayName}}(I_1,...,I_n)
+ = \Macro{\Variable{ArrayName}}(I_n + (I_{n-1}-1) *
+ \Macro{dataheight} + \cdots
+ + (I_1-1) * \Macro{dataheight}^{n-1})$$
+
+ and if !\normalindextrue!, we have:
+ $$\hspace{-3cm}\Macro{\Variable{ArrayName}}(I_1,...,I_n)
+ = \Macro{\Variable{ArrayName}}(I_1 + (I_2-1) *
+ \Macro{dataheight} + \cdots
+ + (I_n-1) * \Macro{dataheight}^{n-1})$$
+ \end{enumerate}
+\end{Description}
+
+\begin{SideBySideExample}[xrightmargin=6cm]
+ \newarray\Letters
+ \readarray{/HLReverse?Letters;}{A&B&C&D&E&F&G&H&I&J}
+ \dataheight=5
+
+ Z\begin{tabular}{c|c|c|c|c|c|c|c|c|}
+ Z \multicolumn{1}{c}{} & \multicolumn{1}{c}{1} & \multicolumn{1}{c}{2} &
+ Z \multicolumn{1}{c}{3} & \multicolumn{1}{c}{4} & \multicolumn{1}{c}{5} \\ \cline{2-6}
+ Z 1 & A & B & C & D & E \\ \cline{2-6}
+ Z 2 & F & G & H & I & J \\ \cline{2-6}
+ Z\end{tabular}
+ Z\\[2mm]
+ % /HLComment?Default is \normalindexfalse;
+ \verb+\Letters(1,2)=+`\Letters(1,2)'
+ Z\par
+ \verb+\Letters(2,1)=+`\Letters(2,1)'
+ Z\\[2mm]
+ Z\begin{tabular}{c|c|c|}
+ Z \multicolumn{1}{c}{} & \multicolumn{1}{c}{1} & \multicolumn{1}{c}{2} \\ \cline{2-3}
+ Z 1 & A & F \\ \cline{2-3}
+ Z 2 & B & G \\ \cline{2-3}
+ Z 3 & C & H \\ \cline{2-3}
+ Z 4 & D & I \\ \cline{2-3}
+ Z 5 & E & J \\ \cline{2-3}
+ Z\end{tabular}
+ Z\\[2mm]
+ \normalindextrue
+ \verb+\Letters(1,2)=+`\Letters(1,2)'
+ Z\par
+ \verb+\Letters(2,1)=+`\Letters(2,1)'
+\end{SideBySideExample}
+
+\begin{Description}{4cm}
+ \item[\FormatTeXMacro{ifexpandarrayelement}] Boolean macro to allow or not
+ the element to be evaluated before to be stored in the array (Default:
+ !\expandarrayelementfalse!).
+
+ Syntax: !\expandarrayelementtrue! or !\expandarrayelementfalse!
+
+ Remark: take care to the possible side effects if you store some macros
+ as values of some array elements without evaluating them, as they can
+ change of content later... (see the following examples).
+\end{Description}
+
+\begin{SideBySideExample}[xrightmargin=6cm]
+ \newarray\Data
+ \newcount\CounterP % /HLComment?Plain TeX usage;
+ \CounterP=3
+ \newcounter{CounterL} % /HLComment?LaTeX usage;
+ \setcounter{CounterL}{3}
+ \def\Town{Madrid}
+ \Data(1)={\the\CounterP}
+ \Data(2)={\the\value{CounterL}}
+ \Data(3)={\Town}
+
+ \expandarrayelementtrue
+ \Data(4)={\the\CounterP}
+ \Data(5)={\the\value{CounterL}}
+ \Data(6)={\Town}
+
+ \CounterP=5
+ \setcounter{CounterL}{5}
+ \def\Town{Roma}
+
+ \multido{\iData=1+1}{6}{%
+ \BS\texttt{Data(\iData)}=`\Data(\iData)'\\}
+\end{SideBySideExample}
+
+\vspace{3mm}
+\noindent Some other macros exists for mono-dimensional arrays (and only for
+them), but have little additional interest:
+
+\begin{Description}{4cm}
+ \item[\FormatTeXMacro{arrayx}] Store or get the content of the array element
+ specified by the index. In the last case, the content is inserted at the
+ current point.\footnote{The macro name \verb|\array| conflicted with macros in {\tt amsmath}, and is changed as of version 1.04. (Modification suggested by Michael Sharpe.)}
+
+ Syntax: !\arrayx/Parameter?/Variable?ArrayName;;(I)=/Parameter?/Variable?Content;;!
+ to store a value
+
+ \hspace{1.3cm}!\arrayx/Parameter?/Variable?ArrayName;;(I)! to retrieve a value
+
+ Examples: !\arrayx{Actors}(6)={Joan Crawford}!
+
+ \hspace{1.75cm}!\arrayx{Actors}(3)!
+
+ \item[\FormatTeXMacro{clrarray}] Clear the content of the array element specified.
+ A following inquiry on this element will give an empty content.
+
+ Syntax: !\clrarray/Parameter?/Variable?ArrayName;;(I)!
+
+ Example: !\clrarray{Actors}(2)!
+
+ \item[\FormatTeXMacro{testarray}] Get the content of the array element specified
+ by the index and store the result in the macro !\temp@macro!%
+ \footnote{In \LaTeX, this macro should be used inside a package or between
+ the \verb+\makeatletter+ $\cdots$ \verb+\makeatother+ macro pair.}.
+
+ Syntax: !\testarray/Parameter?/Variable?ArrayName;;(I)!
+
+ Example: !\testarray{Actors}(1)\typeout{Actors(1)=`\temp@macro'}!
+\end{Description}
+
+\section{Examples}
+
+\UndefineShortVerb{\!} % We will use the ! character in the next examples
+
+ We will first show some basic and easy examples, before looking at more
+advanced ones to solve some complex problems, which require more knowledge of
+\TeX{} programming techniques.
+
+\subsection{Basic examples}
+
+ The immediate thing for which we can use arrays is to store and retrieve
+information:
+
+\vspace{2mm}
+\begin{SideBySideExample}[xrightmargin=6cm]
+ \newarray\Actors
+ \newarray\Dates
+ \newarray\Sexes
+
+ \readarray{/HLReverse?Actors;}{Louise Brooks&Marlene Dietrich&Clark Gable}
+ \readarray{/HLReverse?Dates;}{1906--1985&1902--1992&1901--1960}
+ \readarray{/HLReverse?Sexes;}{2&2&1}
+
+ \begin{description}
+ \item[\Actors(1)] : \Dates(1)
+ \item[\Actors(2)] : \Dates(2)
+ \item[\Actors(3)] : \Dates(3)
+ \end{description}
+\end{SideBySideExample}
+
+\vspace{2mm}
+ But we can also use a general loop macro, as the one provided by the
+\MultiDoPackage{} package, for more powerful usage and a management
+independent of the number of elements:
+
+\vspace{2mm}
+\begin{SideBySideExample}[xrightmargin=6cm]
+ \newcommand{\NumberActors}{3}
+
+ \begin{description}
+ \multido{\iActor=1+1}{\NumberActors}{%
+ \item[\Actors(\iActor)] : \Dates(\iActor)}
+ \end{description}
+\end{SideBySideExample}
+
+\vspace{2mm}
+ This allow various usage in the formatting of texts. A common usage is for a
+\emph{mailing} process, when we must compose some similar letters to various
+people (as we said previously, this was the reason for which these macros were
+developed in the \FormLettPackage{} package). Here, the usage of a programming
+language allow a great flexibility, using some conditionals to format the text
+differently or even to insert different pieces of text according to the person:
+
+\newcommand{\NumberActors}{3}
+
+\begin{CenterExample}
+ \newcounter{iActor}
+
+ \newcommand{\AccordingSexe}[2]{%
+ \checkSexes(\the\value{iActor})%
+ \ifthenelse{\equal{\cachedata}{1}}{#1}{#2}}
+
+ \whiledo{\value{iActor} < \NumberActors}{%
+ \stepcounter{iActor}%
+ \fbox{%
+ \begin{minipage}{0.985\textwidth}
+ Dear \AccordingSexe{Mr}{Mrs} \Actors(\the\value{iActor}),
+
+ I would like to tell you how I admire the great \AccordingSexe{actor}{actress}
+ you are, etc.
+ \end{minipage}}\\[5mm]}
+\end{CenterExample}
+
+ Nevertheless, people who know a little \TeX{} as a programming language know
+that it behaviour is full of pitfalls... For instance, the following example,
+which format a table according to the content of entries stored in external
+arrays, can't work:
+
+\begin{Verbatim}
+ \begin{tabular}{|l|c|}
+ \hline
+ \multicolumn{1}{|c}{\textbf{Actors}} & \multicolumn{1}{|c|}{\textbf{Dates}} \\ \hline
+ \multido{\iActor=1+1}{\NumberActors}{\Actors(\iActor) & \Dates(\iActor) \\ \hline}
+ \end{tabular}
+\end{Verbatim}
+
+ This is because there is an implicit grouping of each entry in a tabular
+environment and that it do not work with the grouping of the \verb+\multido+
+loop. So, this must be program in a different way, storing all the content of
+the table before really inserting it:
+
+\begin{SideBySideExample}[xrightmargin=6cm,baselinestretch=0.9]
+ \begin{tabular}{|l|c|}
+ \hline
+ \multicolumn{1}{|c}{\textbf{Actors}} &
+ \multicolumn{1}{|c|}{\textbf{Dates}} \\ \hline
+ \let\ListActors\empty
+ \begingroup
+ \let\Actors\relax
+ \let\Dates\relax
+ \let\\\relax
+ \let\hline\relax
+ \multido{\iActor=1+1}{\NumberActors}{%
+ \xdef\ListActors{\ListActors
+ \Actors(\iActor) & \Dates(\iActor) \\ \hline}}
+ \endgroup
+ \ListActors
+ \end{tabular}
+\end{SideBySideExample}
+
+\subsubsection{Plot labels}
+
+ A basic usage in graphic programming is to use arrays to retrieve the labels
+to put on a drawing, as here to label the simple plot below. (Note the change from the original documentation. The axis labels used with \verb|\psaxes| must now be numeric, so it is necessary to bypass the automatic axis labeling.)
+\ifpstricks % If PSTricks is available
+\begin{CenterExample}[baselinestretch=0.9]
+ \savedata{\Data}[(1,3)(2,1)(3,2)(4,1)(5,1)(6,3),(7,2)(8,1)(9,3)(10,3)(11,1)(12,1)]
+
+ \newcommand{\PlotData}[1]{%
+ \begin{pspicture}(-0.5,-0.5)(13,4)
+ \psaxes[labels=none]{->}(13,4)
+ \dataplot[plotstyle=dots,dotstyle=o,dotsize=0.3]{\Data}
+ #1\end{pspicture}}
+ \PlotData{\psaxes[showorigin=false]{->}(13,4)}
+
+ \newarray{\Months}
+ \readarray{/HLReverse?Months;}{January&February&March&April&May&June&July&August&September&%
+ October&November&December}
+ \newarray{\Levels}
+ \readarray{/HLReverse?Levels;}{Low&Medium&High}
+ %\renewcommand{\pshlabel}[1]{\tiny\Months(#1)}
+ \PlotData{\psaxes[labels=y,showorigin=false]{->}(13,4)%
+ \multido{\i=1+1}{12}{\rput[B](\i,-12pt){\tiny\Months(\i)}}}
+
+ %\renewcommand{\psvlabel}[1]{\small\Levels(#1)}
+ \PlotData{\multido{\i=1+1}{12}{\rput[B](\i,-12pt){\tiny\Months(\i)}}%
+ \multido{\i=1+1}{3}{\rput[r](-12pt,\i){\small\Levels(\i)}}}
+\end{CenterExample}
+\else
+ \PSTricksExampleNotShown
+\fi % End \pstrickstrue
+
+\subsubsection{Checkboard drawing}
+
+ Of course, a bi-dimensional array directly allow to store the state of a
+checkboard of one of the numerous ones existing, like the reversi game that
+we will show here (in fact, the only more difficult part to understand in this
+example concern the definition of the elementary piece, but as this is not
+related at all to the usage of \ArrayJobPackage, this point can be forgotten
+by most of the readers).
+
+\ifpstricks % If PSTricks is available
+\begin{SideBySideExample}[xrightmargin=6cm,baselinestretch=0.89]
+ /HLMacro?\def\Black;{B}
+ /HLMacro?\def\White;{W}
+
+ /HLMacro?\def\Piece;#1#2{{%
+ \psset{unit=0.8}%
+ \pspicture(0,-0.1)(1,0.8)
+ \pscustom[fillstyle=gradient,gradmidpoint=0,gradangle=90,
+ gradbegin=#2,gradend=#1]{%
+ \psbezier(0,0.2)(0.1,-0.2)(0.9,-0.2)(1,0.2)
+ \psline(1,0.2)(1,0.5)
+ \psbezier(1,0.5)(0.9,0.9)(0.1,0.9)(0,0.5)
+ \psline(0,0.5)(0,0.2)}
+ \psbezier(0,0.5)(0.1,0.1)(0.9,0.1)(1,0.5)
+ \endpspicture}}
+
+ /HLMacro?\def\PieceBlack;{\Piece{black}{gray}}
+ /HLMacro?\def\PieceWhite;{\Piece{white}{gray}}
+
+ /HLMacro?\def\CheckboardHook;{}
+
+ \newarray\Checkboard
+
+ /HLMacro?\def\ShowCheckboard;{%
+ \dataheight=8
+ \pspicture(8,8)
+ \psgrid[subgriddiv=0,gridlabels=0](8,8)
+ \CheckboardHook
+ \multido{\iColumn=1+1,\iColumnPos=0+1}{8}{%
+ \multido{\iRow=1+1,\iRowPos=7+-1}{8}{%
+ \checkCheckboard(\iRow,\iColumn)%
+ \ifx\cachedata\Black
+ \rput(\iColumnPos.5,\iRowPos.5){\PieceBlack}
+ \else
+ \ifx\cachedata\White
+ \rput(\iColumnPos.5,\iRowPos.5){\PieceWhite}
+ \fi
+ \fi}}
+ \endpspicture}
+
+ \readarray{/HLReverse?Checkboard;}{%
+ W& &B& & & & &B&%
+ &W&B& & & & &B&%
+ W&W&B& &W& & &B&%
+ W&W&B&W&W&W&B&B&%
+ B& &W&W&W&B&W&B&%
+ B&B&W&W&W&B&W&B&%
+ B&B&B&W&W&W&W&B&%
+ W&B&B&B&B&B&B&B&%
+ }
+
+ \psset{unit=0.6}
+ \ShowCheckboard
+
+ \Checkboard(2,1)={B} % /HLComment?Black move;
+ /HLMacro?\def\CheckboardHook;{%
+ \psframe[linestyle=none,fillstyle=hlines](0,6)(1,7)}
+ % /HLComment?White pieces changed by the black move;
+ \Checkboard(3,1)={B}\Checkboard(4,1)={B}
+ \Checkboard(2,2)={B}\Checkboard(3,2)={B}
+ \vspace{1cm}
+ \ShowCheckboard
+\end{SideBySideExample}
+\else
+ \PSTricksExampleNotShown
+\fi % End \pstrickstrue
+
+ Note also that, if \TeX{} is obviously not well suited to implement a
+program to \emph{really} play at a game like reversi or chess, nevertheless
+it can be used to solve internally some non trivial algorithmic problems,
+where the usage of arrays help a lot. For such example (on the coloration of
+the Truchet's tiling), see \cite{EG98}.
+
+\subsection{Advanced examples}
+
+ This section will show slightly more difficult to really complex examples,
+and is mainly for \emph{advanced users} or for people who want to be able to
+program complex tasks themselves.
+
+\subsubsection{Example with recursion usage}
+
+\begin{CenterExample}
+ \makeatletter
+
+ % /HLComment?The recursion macro used (from David Carlisle);
+ /HLMacro?\def\Recursion;#1{%
+ #1\relax
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi}
+
+ \newcount\IndexRecursion
+ \IndexRecursion=\z@
+
+ /HLMacro?\def\PiFrac;#1{{%
+ \Recursion
+ {\ifnum#1>\@ne\relax}
+ {\@tempcnta=#1
+ \advance\@tempcnta\m@ne
+ \advance\IndexRecursion\@ne
+ \PiValues(\IndexRecursion)
+ +\frac{\strut\displaystyle 1}{\strut\displaystyle\PiFrac{\@tempcnta}}}
+ {\advance\IndexRecursion\@ne
+ \PiValues(\IndexRecursion)}}}
+
+ \makeatother
+
+ \newarray\PiValues
+ \readarray{/HLReverse?PiValues;}{3&7&15&1&292&1&1&1&2&1&3&1&14}
+
+ \(\pi\approx\PiFrac{/HLReverse?4;}\approx\PiFrac{/HLReverse?13;}\)
+
+ \textbf{\(\pi\) as a continued fraction}
+\end{CenterExample}
+
+\subsubsection{Structured dynamic diagrams on a grid}
+
+ A very common case is when we must use some strutured data which are to be
+drawn on a kind of abstract grid.
+
+\ifpstricks % If PSTricks is available
+ To draw a diagram like this one (such example illustrate the exchanges of
+data between processors when using applications on multiprocessors computers
+in parallel programming):
+
+\vspace{2mm}
+\begin{SideBySideExample}[xrightmargin=5.8cm]
+ \psset{linestyle=none,fillstyle=solid,subgriddiv=0,gridlabels=0}
+ \begin{pspicture}(-1,0)(4,4)
+ % /HLComment?Line 0;
+ \psframe[fillcolor=Khaki](0,3.1)(1,3.9)
+ \psframe[fillcolor=LemonChiffon](1,3.1)(4,3.9)
+ \rput(0,3.1){\psgrid[yunit=0.8](4,1)}
+ \rput(-0.5,3.5){P0}
+ \rput(0.5,3.5){A0}
+ % /HLComment?Line 1;
+ \psframe[fillcolor=Khaki](0,2.1)(2,2.9)
+ \psframe[fillcolor=LemonChiffon](2,2.1)(4,2.9)
+ \rput(0,2.1){\psgrid[yunit=0.8](4,1)}
+ \rput(-0.5,2.5){P1}
+ \rput(0.5,2.5){A0}\rput(1.5,2.5){A1}
+ % /HLComment?Line 2;
+ \psframe[fillcolor=Khaki](0,1.1)(3,1.9)
+ \psframe[fillcolor=LemonChiffon](3,1.1)(4,1.9)
+ \rput(0,1.1){\psgrid[yunit=0.8](4,1)}
+ \rput(-0.5,1.5){P2}
+ \rput(0.5,1.5){A0}\rput(1.5,1.5){A1}\rput(2.5,1.5){A2}
+ % /HLComment?Line 3;
+ \psframe[fillcolor=Khaki](0,0.1)(4,0.9)
+ \rput(0,0.1){\psgrid[yunit=0.8](4,1)}
+ \rput(-0.5,0.5){P3}
+ \rput(0.5,0.5){A0}\rput(1.5,0.5){A1}
+ \rput(2.5,0.5){A2}\rput(3.5,0.5){A3}
+ \end{pspicture}
+\end{SideBySideExample}
+
+\vspace{2mm}
+\noindent is easy but rather painful, as we must manage a lot of coordinates.
+Nevertheless, even if we introduce a little more abstraction level using some
+minor programming with a loop structure:
+\vspace{2mm}
+
+
+\begin{SideBySideExample}[xrightmargin=5.8cm]
+ \psset{linestyle=none,fillstyle=solid,subgriddiv=0,gridlabels=0}
+ \begin{pspicture}(-1,0)(4,4)
+ \multido{\iLoop=1+1,\iRow=0+1,\iRowPos=3+-1}{4}{%
+ \psframe[fillcolor=Khaki](0,\iRowPos.1)(\iLoop,\iRowPos.9)
+ \psframe[fillcolor=LemonChiffon]
+ (\iLoop,\iRowPos.1)(4,\iRowPos.9)
+ \rput(0,\iRowPos.1){\psgrid[yunit=0.8](4,1)}
+ \rput(-0.5,\iRowPos.5){P\iRow}
+ \multido{\iColumn=0+1,\iLabel=1+1}{\iLoop}{%
+ \rput(\iColumn.5,\iRowPos.5){A\iColumn}}}
+ \end{pspicture}
+\end{SideBySideExample}
+
+\vspace{2mm}
+\noindent we succeed to heavily reduce the number of lines of the code in this
+specific case, but we gain nothing in genericity. If we have several such
+diagrams to draw, with each that must be done differently according to the
+empty and full cells of the array, we must proceed in a completely different
+way, defining a \emph{generic object} which can obtain the different values of
+a data structure previously filled. For such tasks, the \ArrayJobPackage{}
+package allow to build very efficient and powerful tools.
+
+\begin{Verbatim}[commandchars=/?;]
+ % /HLComment?The grid;
+ /HLMacro?\def\ArrayGrid;#1#2#3{{%
+ % /HLComment?#1=array of data, #2=number of rows, #3=number of columns;
+ \psset{dimen=middle,xunit=0.8}
+ \dataheight=#3
+ \pspicture(-1,-#2)(#3,0)
+ \multido{\iRow=1+1,\iRowMinusOne=0+1}{#2}{%
+ \rput(-1,-\iRow){\LineGrid{#1}{\iRow}{\iRowMinusOne}{#3}}}
+ \endpspicture}}
+
+ % /HLComment?One line of the grid;
+ /HLMacro?\def\LineGrid;#1#2#3#4{%
+ \rput(0.5,0.4){\AttributeLabel{P#3}}
+ \multido{\iColumn=1+1}{#4}{%
+ \expandafter\csname check#1\endcsname(#2,\iColumn)%
+ \rput(\iColumn,0){%
+ \ifemptydata
+ \def\ColorBackground{\ColorBackgroundEmpty}%
+ \else
+ \ifx\cachedata\space
+ \def\ColorBackground{\ColorBackgroundEmpty}%
+ \else
+ \def\ColorBackground{\ColorBackgroundFull}%
+ \fi
+ \fi
+ \psframe[fillstyle=solid,fillcolor=\ColorBackground](1,0.8)
+ \rput(0.5,0.4){\AttributeElement{\cachedata}}}}}
+\end{Verbatim}
+
+% The grid
+\def\ArrayGrid#1#2#3{{%
+% #1=array of data, #2=number of rows, #3=number of columns
+\psset{dimen=middle,xunit=0.8}
+\dataheight=#3
+\pspicture(-1,-#2)(#3,0)
+\multido{\iRow=1+1,\iRowMinusOne=0+1}{#2}{%
+ \rput(-1,-\iRow){\LineGrid{#1}{\iRow}{\iRowMinusOne}{#3}}}
+\endpspicture}}
+
+% One line of the grid
+\def\LineGrid#1#2#3#4{%
+\rput(0.3,0.4){\AttributeLabel{P#3}}
+\multido{\iColumn=1+1}{#4}{%
+ \expandafter\csname check#1\endcsname(#2,\iColumn)%
+ \rput(\iColumn,0){%
+ \ifemptydata
+ \def\ColorBackground{\ColorBackgroundEmpty}%
+ \else
+ \ifx\cachedata\space
+ \def\ColorBackground{\ColorBackgroundEmpty}%
+ \else
+ \def\ColorBackground{\ColorBackgroundFull}%
+ \fi
+ \fi
+ \psframe[fillstyle=solid,fillcolor=\ColorBackground](1,0.8)
+ \rput(0.5,0.4){\AttributeElement{\cachedata}}}}}
+
+\begin{SideBySideExample}[xrightmargin=6cm]
+ % /HLComment?Default attributes;
+ \def\ColorBackgroundEmpty{LemonChiffon}
+ \def\ColorBackgroundFull{Khaki}
+ \def\AttributeElement#1{\textcolor{red}{#1}}
+ \def\AttributeLabel#1{\bf #1}
+
+ % /HLComment?Example 1;
+ \newarray\ArrayA
+
+ % /HLComment?Data;
+ \readarray{/HLReverse?ArrayA;}{%
+ A0& & & &%
+ A0&A1& & &%
+ A0&A1&A2& &%
+ A0&A1&A2&A3}
+
+ \ArrayGrid{ArrayA}{4}{4}
+\end{SideBySideExample}
+
+\newarray\ArrayA
+
+% Default attributes
+\def\ColorBackgroundEmpty{LemonChiffon}
+\def\ColorBackgroundFull{Khaki}
+\def\AttributeElement#1{\textcolor{red}{#1}}
+\def\AttributeLabel#1{\bf #1}
+
+\begin{CenterExample}[baselinestretch=0.9]
+ % /HLComment?Example 2;
+ \newarray\ArrayB
+
+ % /HLComment?Data;
+ \readarray{/HLReverse?ArrayA;}{%
+ A& & & &%
+ & & & &%
+ & & & &%
+ & & & }
+ \readarray{/HLReverse?ArrayB;}{%
+ A& & & &%
+ A& & & &%
+ A& & & &%
+ A& & & }
+
+ \ArrayGrid{ArrayA}{4}{4}\hfill\ArrayGrid{ArrayB}{4}{4}
+\end{CenterExample}
+
+\newarray\ArrayB
+
+\begin{CenterExample}[baselinestretch=0.9]
+ % /HLComment?Example 3;
+ \newarray\ArrayC
+
+ % /HLComment?Data;
+ \readarray{/HLReverse?ArrayA;}{%
+ A0& & &%
+ A1& & &%
+ A2& & }
+ \readarray{/HLReverse?ArrayB;}{%
+ A0&A1&A2&%
+ A0&A1&A2&%
+ A0&A1&A2}
+ \readarray{/HLReverse?ArrayC;}{%
+ A0& & &%
+ &A1& &%
+ & &A2}
+
+ % /HLComment?Attributes;
+ \def\ColorBackgroundEmpty{green}
+ \def\ColorBackgroundFull{red}
+ \def\AttributeElement#1{\footnotesize\textcolor{white}{#1}}
+ \def\AttributeLabel#1{\small\bf #1}
+
+ \psset{unit=0.7}
+ \ArrayGrid{ArrayA}{3}{3}\hfill\ArrayGrid{ArrayB}{3}{3}\hfill\ArrayGrid{ArrayC}{3}{3}
+\end{CenterExample}
+
+\begin{CenterExample}[baselinestretch=0.9]
+ % /HLComment?Example 4;
+
+ % /HLComment?Data;
+ \readarray{/HLReverse?ArrayA;}{%
+ A0&A1&A2&A3&%
+ B0&B1&B2&B3&%
+ C0&C1&C2&C3&%
+ D0&D1&D2&D3}
+ \readarray{/HLReverse?ArrayB;}{%
+ A0&B0&C0&D0&%
+ A1&B1&C1&D1&%
+ A2&B2&C2&D2&%
+ A3&B3&C3&D3}
+
+ % /HLComment?Attributes;
+ \def\AttributeElement#1{\textcolor{red}{#1}}
+ \def\AttributeLabel#1{\Large\it #1}
+
+ \ArrayGrid{ArrayA}{4}{4}\hfill\ArrayGrid{ArrayB}{4}{4}
+\end{CenterExample}
+\else
+ \PSTricksExampleNotShown
+\fi % End \pstrickstrue
+
+\vspace{5mm}
+\subsubsection{Another example of a structured dynamic diagram on a grid}
+
+ The preceding technique is in fact relevant for a lot of problems. Here we
+give another example about the drawing of linked lists (but do not fail to
+note that these ones have here no internal existence).
+
+\ifpstricks % If PSTricks is available
+\begin{CenterExample}
+ \makeatletter
+
+ \newpsstyle{LinkedListsArrowStyle}{linecolor=red,arrowscale=2} % /HLComment?Default arrow style;
+
+ /HLMacro?\def\LinkedListsDraw;{\@ifnextchar[\LinkedListsDraw@i{\LinkedListsDraw@i[]}}
+
+ /HLMacro?\def\LinkedListsDraw@i;[#1]#2#3{{%
+ \setkeys{psset}{#1}
+ \dataheight=#3
+ %
+ \pst@cnta=#3
+ \multiply\pst@cnta\tw@
+ \advance\pst@cnta\tw@
+ \pspicture(0,-#2)(\pst@cnta,0)
+ \multido{\iRow=1+1}{#2}{%
+ \rput(0,-\iRow){%
+ \psframe(1,1)
+ \psline[dimen=middle,style=LinkedListsArrowStyle]{->}(0.5,0.5)(2,0.5)}
+ \multido{\iColumn=1+1}{#3}{%
+ \checkLinkedListsTable(\iRow,\iColumn)%
+ \ifemptydata
+ \else
+ \pst@cnta=\iColumn
+ \advance\pst@cnta\@ne
+ \pst@cntb=\@ne
+ \checkLinkedListsTable(\iRow,\pst@cnta)%
+ \ifemptydata % /HLComment?We test if it is empty;
+ \else
+ \ifnum\multidocount=#3 % /HLComment?We test if it is the last one;
+ \else
+ \pst@cntb=\z@
+ \fi
+ \fi
+ %
+ \pst@cnta=\iColumn
+ \multiply\pst@cnta\tw@
+ \rput(\the\pst@cnta,-\iRow){%
+ \LinkedListsDraw@ii{\LinkedListsTable(\iRow,\iColumn)}{\the\pst@cntb}}
+ \fi}}
+ \endpspicture}}%}
+
+ /HLMacro?\def\LinkedListsDraw@ii;#1#2{{%
+ \rput(0,0.1){%
+ \psset{unit=0.8}
+ \psgrid[subgriddiv=0,gridlabels=0](2,1) % /HLComment?Element;
+ \rput(0.5,0.5){#1} % /HLComment?Label for this element;
+ \ifnum#2=\@ne
+ \psline(1,0)(2,1) % /HLComment?Mark of the end of the list;
+ \else
+ \psline[style=LinkedListsArrowStyle]{->}(1.5,0.5)(2.5,0.5) % /HLComment?Link to the next element;
+ \fi}}}
+
+ \makeatother
+
+ \newarray\LinkedListsTable
+ \readarray{/HLReverse?LinkedListsTable;}{%
+ 11&12&13&14&%
+ 21&&&&%
+ 31&32&33&&}
+
+ \LinkedListsDraw{3}{4}
+
+ \vspace{1cm}
+ \newpsstyle{LinkedListsArrowStyle}{linecolor=green,doubleline=true}
+
+ \readarray{/HLReverse?LinkedListsTable;}{%
+ a&&&&&%
+ A&B&C&D&E&%
+ 0&1&2&3&4&%
+ +&$\times$&&&&}
+
+ \LinkedListsDraw{4}{5}
+\end{CenterExample}
+\else
+ \PSTricksExampleNotShown
+\fi % End \pstrickstrue
+
+\subsubsection{Management of heaps and linked lists}
+
+ Here we will demonstrate a really more complex usage, but very useful.
+In fact, if the \ArrayJobPackage{} package primarily allow to manage only
+arrays, it allow a lot more with some efforts. Above it, we can implement the
+common internal data structures frequently used in programming, like heaps,
+simple or double linked lists, trees, associative arrays, etc. Here we will
+show how to define macros to build and manage heaps and simple linked lists.
+
+\ifpstricks % If PSTricks is available
+\vspace{1cm} % Poor hack to force a page break...
+\begin{CenterExample}[baselinestretch=0.98]
+ \makeatletter
+
+ /HLMacro?\def\PstDebug;{\z@} % /HLComment?For debugging, set \def\PstDebug{1};
+
+ % /HLComment?Code for heaps management;
+ % /HLComment?-------------------------;
+
+ /HLMacro?\def\HeapMaxDepth;{100} % /HLComment?No more than 100 elements in the heap;
+
+ \newarray\Heap
+
+ % /HLComment?Add an element at top of the heap;
+ /HLMacro?\def\HeapPush;#1{%
+ \multido{\iElem=1+1}{\HeapMaxDepth}{%
+ \checkHeap(\iElem)%
+ \ifemptydata
+ \ifnum\PstDebug=\@ne\typeout{Push Heap(\iElem)=#1}\fi% /HLComment?Debug;
+ \Heap(\iElem)={#1}%
+ \multidostop
+ \fi}}
+
+ % /HLComment?Get (in the \cachedata macro) and delete the element at top of the heap;
+ /HLMacro?\def\HeapPop;{%
+ \Multido{\iElem=\HeapMaxDepth+-1}{\HeapMaxDepth}{%
+ \checkHeap(\iElem)%
+ \ifemptydata
+ \else
+ \ifnum\PstDebug=\@ne\typeout{Delete Heap(\iElem)=\cachedata}\fi% /HLComment?Debug;
+ \Heap(\iElem)={}%
+ \multidostop
+ \fi}}
+
+ % /HLComment?Print the current state of the heap;
+ /HLMacro?\def\HeapPrint;{%
+ \checkHeap(\@ne)%
+ \ifemptydata
+ \typeout{The heap is empty!}% /HLComment?Empty heap;
+ \else
+ \multido{\iElem=\HeapMaxDepth+-1}{\HeapMaxDepth}{%
+ \checkHeap(\iElem)%
+ \ifemptydata
+ \else
+ \typeout{Heap(\iElem)=\cachedata}%
+ \fi}
+ \fi
+ \typeout{}}
+
+ % /HLComment?Draw the current state of the heap;
+ /HLMacro?\def\HeapDraw;{%
+ % /HLComment?To compute the size of the picture;
+ \Multido{\iSize=0+1}{\HeapMaxDepth}{%
+ \checkHeap(\the\multidocount)%
+ \ifemptydata
+ \multidostop
+ \fi}
+ %
+ \ifnum\iSize=\z@
+ % /HLComment?Empty heap;
+ \typeout{The heap is empty!^^J}%
+ \else
+ \pspicture(1,\iSize)
+ \psgrid[subgriddiv=0,gridlabels=0](1,\iSize)
+ \multido{\iPos=0+1}{\HeapMaxDepth}{%
+ \checkHeap(\the\multidocount)%
+ \ifemptydata
+ \multidostop
+ \else
+ \rput(0.5,\iPos.5){\cachedata}
+ \fi}
+ \endpspicture%
+ \fi}
+
+ \makeatother
+
+ \psset{unit=1.5}\footnotesize
+
+ \HeapPush{Germany}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPush{France}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPush{Italy}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPush{Spain}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPop\typeout{Popped element: `\cachedata'}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPop\typeout{Popped element: `\cachedata'}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPop\typeout{Popped element: `\cachedata'}\HeapPrint\HeapDraw
+ \hfill
+ \HeapPop\typeout{Popped element: `\cachedata'}\HeapPrint\HeapDraw
+\end{CenterExample}
+
+\begin{Example}[baselinestretch=0.95]
+ \makeatletter
+
+ /HLMacro?\def\PstDebug;{\z@}% /HLComment?For debugging, set \def\PstDebug{1};
+
+ % /HLComment?Code for linked lists management;
+ % /HLComment?--------------------------------;
+
+ /HLMacro?\def\LinkedListMaxDepth;{100}% /HLComment?No more than 100 elements in the list;
+
+ \newarray\LinkedList
+
+ \dataheight=2% /HLComment?Two cells by element: the content and the pointer;
+
+ % /HLComment?Add an element at the end of the list;
+ % /HLComment?In fact, we define it here as a simple heap, but the difference is that;
+ % /HLComment?we will be able to get and to delete any element in it;
+ /HLMacro?\def\LinkedListAdd;#1{%
+ \edef\@tempa{\@ne}% /HLComment?Pointer initialization;
+ \multido{\iElem=2+1}{\LinkedListMaxDepth}{%
+ \checkLinkedList(\@tempa,2)% /HLComment?We got the content of this element;
+ \ifemptydata
+ % /HLComment?No pointed element, so we will insert the new one here;
+ \LinkedList(\iElem,1)={#1}%
+ % /HLComment?We update the pointer for the last preceding element;
+ \expandarrayelementtrue% /HLComment?We must evaluate the content of the counter;
+ \LinkedList(\@tempa,2)={\iElem}%
+ \expandarrayelementfalse
+ \ifnum\PstDebug=\@ne
+ \typeout{Add LinkedList(\@tempa)->\iElem}% /HLComment?Debug;
+ \typeout{\space\space\space\space LinkedList(\iElem)=#1}% /HLComment?Debug;
+ \fi
+ \multidostop
+ \else
+ \edef\@tempa{\cachedata}%
+ \fi}}
+
+ % /HLComment?Get (in the \cachedata macro) the next element in the list;
+ /HLMacro?\def\LinkedListGetNext;#1{%
+ \checkLinkedList(1,2)% /HLComment?We got the pointer for the first element;
+ \edef\@tempa{\@ne}%
+ \ifx\cachedata\empty
+ \else
+ \edef\@tempc{#1}%
+ \Multido{}{\LinkedListMaxDepth}{%
+ \edef\@tempb{\@tempa}%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% /HLComment?We got the pointed element;
+ \ifx\cachedata\@tempc
+ % /HLComment?This is the element for which we want the next one: we got it pointer;
+ % /HLComment?to the next element in the list, then the content of it;
+ \checkLinkedList(\@tempa,2)%
+ \ifemptydata
+ \typeout{Element `#1' has no successor!^^J}%
+ \else
+ \checkLinkedList(\cachedata,1)%
+ \fi
+ \multidostop
+ \else
+ \checkLinkedList(\@tempa,2)% /HLComment?We got the pointer to the next element;
+ \ifemptydata
+ % /HLComment?We have reach the end of the list without finding the element;
+ \typeout{Element `#1' not found!^^J}%
+ \multidostop% /HLComment?No pointed element: end of the list;
+ \fi
+ \fi}
+ \fi}
+
+ % /HLComment?Delete an element in the list (the code is very close to \LinkedListGetNext);
+ /HLMacro?\def\LinkedListDelete;#1{%
+ \checkLinkedList(1,2)% /HLComment?We got the pointer for the first element;
+ \edef\@tempa{\@ne}%
+ \ifx\cachedata\empty
+ \else
+ \edef\@tempc{#1}%
+ \multido{}{\LinkedListMaxDepth}{%
+ \edef\@tempb{\@tempa}%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% /HLComment?We got the pointed element;
+ \ifx\cachedata\@tempc
+ % /HLComment?This is the element to delete: we will update the pointer of;
+ % /HLComment?the preceding element to the value of the pointer of the deleted one;
+ \checkLinkedList(\@tempa,2)%
+ \expandarrayelementtrue
+ \LinkedList(\@tempb,2)={\cachedata}%
+ \expandarrayelementfalse
+ \ifnum\PstDebug=\@ne
+ \typeout{Delete LinkedList(\@tempa)=#1}% /HLComment?Debug;
+ \typeout{\space\space\space\space\space\space\space %
+ LinkedList(\@tempb)->\cachedata}% /HLComment?Debug;
+ \fi
+ \multidostop
+ \else
+ \checkLinkedList(\@tempa,2)% /HLComment?We got the pointer to the next element;
+ \ifemptydata
+ % /HLComment?We have reach the end of the list without finding the element;
+ \typeout{Element `#1' not found and so not deleted!^^J}%
+ \multidostop% /HLComment?No pointed element: end of the list;
+ \fi
+ \fi}
+ \fi}
+
+ % /HLComment?Print the current state of the list;
+ /HLMacro?\def\LinkedListPrint;{%
+ \checkLinkedList(1,2)% /HLComment?We got the pointer for the first element;
+ \ifx\cachedata\empty
+ % /HLComment?Empty list;
+ \typeout{The list is empty!}%
+ \else
+ \multido{}{\LinkedListMaxDepth}{%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% /HLComment?We got the pointed element;
+ \typeout{LinkedList=\cachedata}%
+ \checkLinkedList(\@tempa,2)% /HLComment?We got the pointer to the next element;
+ \ifemptydata
+ \multidostop% /HLComment?No pointed element: end of the list;
+ \fi}
+ \fi
+ \typeout{}}
+
+ % /HLComment?Draw the current state of the list;
+ /HLMacro?\def\LinkedListDraw;{{%
+ \psset{subgriddiv=0,gridlabels=0}
+ \checkLinkedList(1,2)% /HLComment?We got the pointer for the first element;
+ \ifx\cachedata\empty
+ % /HLComment?Empty list;
+ \typeout{The list is empty!^^J}%
+ \else
+ % /HLComment?To compute the size of the picture;
+ \Multido{\iSize=3+3}{\LinkedListMaxDepth}{%
+ \checkLinkedList(\cachedata,2)% /HLComment?We got the pointer to the next element;
+ \ifemptydata
+ \multidostop
+ \fi}
+ %
+ \checkLinkedList(1,2)% /HLComment?We got the pointer for the first element;
+ \pspicture(\iSize,1.5)
+ \multido{\iPos=0+3}{\LinkedListMaxDepth}{%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% /HLComment?We got the pointed element;
+ \rput(\iPos,0){%
+ \psgrid(2,1)
+ \rput(0.5,0.5){\cachedata}
+ \ifnum\iPos=\z@
+ \else
+ \rput(-1.5,0.5){\psline[linecolor=red,arrowscale=2]{->}(1.5,0)}
+ \fi}
+ \checkLinkedList(\@tempa,2)% /HLComment?We got the pointer to the next element;
+ \ifemptydata
+ \rput(\iPos,0){\psline[linecolor=red](1,0)(2,1)} % /HLComment?End of the list;
+ \multidostop% /HLComment?No pointed element: end of the list;
+ \fi}
+ \endpspicture%
+ \fi}}
+
+ \makeatother
+
+ \psset{unit=1.5}
+
+ \LinkedListPrint\LinkedListDraw
+
+ \LinkedListAdd{Germany}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListAdd{France}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListAdd{Italy}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListAdd{Spain}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListGetNext{France}\typeout{Next element after `France' is: `\cachedata'}%
+ \LinkedListGetNext{Germany}\typeout{Next element after `Germany is: `\cachedata'}%
+ \LinkedListGetNext{Spain}
+ \LinkedListGetNext{Unknown}
+
+ \LinkedListDelete{Unknown}
+
+ \LinkedListDelete{France}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{Germany}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{Spain}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{Italy}\LinkedListPrint\LinkedListDraw
+\end{Example}
+
+\makeatletter
+
+\def\PstDebug{\z@}% For debugging, set \def\PstDebug{1}
+
+\def\LinkedListMaxDepth{100}% No more than 100 elements in the heap
+
+\newarray\LinkedList
+
+\dataheight=2% Two cells by element: the content and the pointer
+
+% Delete an element in the list
+\def\LinkedListDelete#1{%
+\checkLinkedList(1,2)% We got the pointer for the first element
+\edef\@tempa{\@ne}%
+\ifx\cachedata\empty
+\else
+ \edef\@tempc{#1}%
+ \multido{}{\LinkedListMaxDepth}{%
+ \edef\@tempb{\@tempa}%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% We got the pointed element
+ \ifx\cachedata\@tempc
+ % This is the element to delete: we will update the pointer of
+ % the preceding element to the value of the pointer of the deleted one
+ \checkLinkedList(\@tempa,2)%
+ \expandarrayelementtrue
+ \LinkedList(\@tempb,2)={\cachedata}%
+ \expandarrayelementfalse
+ \ifnum\PstDebug=\@ne
+ \typeout{Delete LinkedList(\@tempa)=#1}%Debug
+ \typeout{\space\space\space\space\space\space\space %
+ LinkedList(\@tempb)->\cachedata}%Debug
+ \fi
+ \multidostop
+ \else
+ \checkLinkedList(\@tempa,2)% We got the pointer to the next element
+ \ifemptydata
+ % We have reach the end of the list without finding the element
+ \typeout{Element `#1' not found and so not deleted!^^J}%
+ \multidostop% No pointed element: end of the list
+ \fi
+ \fi}
+\fi}
+
+% Print the current state of the list
+\def\LinkedListPrint{%
+\checkLinkedList(1,2)% We got the pointer for the first element
+\ifx\cachedata\empty
+ % Empty list
+ \typeout{The list is empty!}%
+\else
+ \multido{}{\LinkedListMaxDepth}{%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% We got the pointed element
+ \typeout{LinkedList=\cachedata}%
+ \checkLinkedList(\@tempa,2)% We got the pointer to the next element
+ \ifemptydata
+ \multidostop% No pointed element: end of the list
+ \fi}
+\fi
+\typeout{}}
+
+% Draw the current state of the list
+\def\LinkedListDraw{{%
+\psset{subgriddiv=0,gridlabels=0}
+\checkLinkedList(1,2)% We got the pointer for the first element
+\ifx\cachedata\empty
+ % Empty list
+ \typeout{The list is empty!^^J}%
+\else
+ % To compute the size of the picture
+ \Multido{\iSize=3+3}{\LinkedListMaxDepth}{%
+ \checkLinkedList(\cachedata,2)% We got the pointer to the next element
+ \ifemptydata
+ \multidostop
+ \fi}
+ %
+ \checkLinkedList(1,2)% We got the pointer for the first element
+ \pspicture(\iSize,1.5)
+ \multido{\iPos=0+3}{\LinkedListMaxDepth}{%
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)% We got the pointed element
+ \rput(\iPos,0){%
+ \psgrid(2,1)
+ \rput(0.5,0.5){\cachedata}
+ \ifnum\iPos=\z@
+ \else
+ \rput(-1.5,0.5){\psline[linecolor=red,arrowscale=2]{->}(1.5,0)}
+ \fi}
+ \checkLinkedList(\@tempa,2)% We got the pointer to the next element
+ \ifemptydata
+ \rput(\iPos,0){\psline[linecolor=red](1,0)(2,1)} % End of the list
+ \multidostop% No pointed element: end of the list
+ \fi}
+ \endpspicture%
+\fi}}
+
+\makeatother
+
+% We clear the linked list
+\multido{\iElem=1+1}{\LinkedListMaxDepth}{%
+ \checkLinkedList(\iElem,1)%
+ \ifemptydata
+ \else
+ \LinkedList(\iElem,1)={}%
+ \LinkedList(\iElem,2)={}%
+ \fi}
+
+\vspace{2mm}
+ We can write an extended version of the inclusion of an element, where we do
+not still store each element at the end of the list, but insert it at a
+special position. For instance, we can decide to use the list to sort the
+elements, inserting a new one at it sorted position. In the next example, we
+will manage integer numbers in this way (of course, we can do the same thing
+with arbitrary strings, but it would be more difficult to program in \TeX{},
+mainly if we want to be able to use accentuated letters).
+
+\vspace{2mm}
+\begin{Example}
+ \makeatletter
+
+ % /HLComment?Add an element at the end of the list, linked in it ordered place;
+ % /HLComment?(this version work only with contents as numbers);
+ /HLMacro?\def\LinkedListSortedAdd;#1{%
+ % /HLComment?Initializations;
+ \edef\@tempa{\@ne}%
+ \edef\@tempb{\@ne}%
+ \edef\@tempc{\z@}%
+ %
+ \multido{\iElem=2+1}{\LinkedListMaxDepth}{%
+ \checkLinkedList(\@tempa,2)% /HLComment?We got the pointer of this element;
+ \ifemptydata
+ % /HLComment?No pointed element, so we will insert the new one here;
+ \LinkedList(\iElem,1)={#1}%
+ % /HLComment?We update the pointer for the last element;
+ \expandarrayelementtrue
+ \LinkedList(\@tempb,2)={\iElem}%
+ \ifnum\PstDebug=\@ne
+ \typeout{Add LinkedList(\@tempb)->\iElem}% /HLComment?Debug;
+ \typeout{\space\space\space\space LinkedList(\iElem)=#1}% /HLComment?Debug;
+ \fi
+ % /HLComment?We update the pointer of the new element to the position;
+ % /HLComment?of the next greater one, if it exist;
+ \ifnum\@tempc=\z@
+ \else
+ \LinkedList(\iElem,2)={\@tempc}%
+ \ifnum\PstDebug=\@ne
+ \typeout{Update LinkedList(\iElem)->\@tempc}% /HLComment?Debug;
+ \fi
+ \fi
+ \expandarrayelementfalse
+ \multidostop
+ \else
+ \edef\@tempa{\cachedata}%
+ \checkLinkedList(\cachedata,1)%
+ \ifnum#1<\cachedata
+ \edef\@tempc{\@tempa}% /HLComment?New element less than this one;
+ \else
+ \edef\@tempb{\@tempa}% /HLComment?New element greater or equal than this one;
+ \fi
+ \fi}}
+
+ \makeatother
+
+ \LinkedListPrint
+
+ \LinkedListSortedAdd{732}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListSortedAdd{487}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListSortedAdd{718}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListSortedAdd{962}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{487}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{732}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{500}
+
+ \LinkedListDelete{962}\LinkedListPrint\LinkedListDraw
+
+ \LinkedListDelete{718}\LinkedListPrint\LinkedListDraw
+\end{Example}
+\else
+ \PSTricksExampleNotShown
+\fi % End \pstrickstrue
+
+\subsubsection{Associative arrays}
+
+ To finish, we will give a complete solution to a classical problem: to count
+the number of occurrences of the various letters in a sentence. For this, we
+will first build some macros to deal with \emph{associative} arrays, as they
+have been popularized by scripting languages like \texttt{AWK} and
+\texttt{Perl}.
+
+\begin{Example}
+ \makeatletter
+
+ % /HLComment?Internally, we use two "standard" arrays to define one associative array;
+ \newarray\AssociativeArray@Names
+ \newarray\AssociativeArray@Values
+
+ \newcount\AssociativeArrayNbValues
+ \AssociativeArrayNbValues=\z@
+
+ \newif\ifAssociativeArray@ElementFound
+
+ % /HLComment?To store one element;
+ /HLMacro?\def\AssociativeArray;(#1)=#2{%
+ \expandarrayelementtrue
+ \AssociativeArray@ElementFoundfalse
+ \edef\@tempa{#1}%
+ \Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \ifx\@tempa\cachedata
+ % /HLComment?This element already exist: we replace it current value;
+ % /HLComment?\checkAssociativeArray@Values(\iValue)% Debug;
+ % /HLComment?\typeout{In #1, replace `\cachedata'\space by `#2'}% Debug;
+ \AssociativeArray@Values(\iValue)={#2}%
+ \AssociativeArray@ElementFoundtrue
+ \multidostop
+ \fi}
+ \ifAssociativeArray@ElementFound
+ \else
+ % /HLComment?New element;
+ \advance\AssociativeArrayNbValues\@ne
+ \AssociativeArray@Names(\AssociativeArrayNbValues)={#1}%
+ \AssociativeArray@Values(\AssociativeArrayNbValues)={#2}%
+ \fi}
+
+ % /HLComment?To get one element;
+ /HLMacro?\def\checkAssociativeArray;(#1){%
+ \edef\@tempa{#1}%
+ \edef\@tempb{999999}%
+ \Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \ifx\@tempa\cachedata
+ % /HLComment?We have found it by name;
+ \edef\@tempb{\iValue}%
+ \multidostop
+ \fi}
+ % /HLComment?We have now to get it value;
+ \checkAssociativeArray@Values(\@tempb)}
+
+ % /HLComment?Simple macro to print all the associative array;
+ /HLMacro?\def\printAssociativeArray;{%
+ \multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \iValue: \BS\texttt{FirstNames(\cachedata)}=`\AssociativeArray@Values(\iValue)'\space}}
+
+ \makeatother
+
+ \let\FirstNames\AssociativeArray
+ \let\checkFirstNames\checkAssociativeArray
+ \let\printFirstNames\printAssociativeArray
+
+ \FirstNames(Crawford)={Joan}
+ \FirstNames(Tierney)={Gene}
+ \FirstNames(Lake)={Veronika}
+
+ \printFirstNames
+
+ \checkFirstNames(Lake)
+ \verb+\FirstNames(Lake)+=`\cachedata'
+
+ \checkFirstNames(Monroe)
+ \ifemptydata
+ \verb+\FirstNames(Monroe) undefined!+
+ \else
+ \verb+\FirstNames(Monroe)+=`\cachedata'
+ \fi
+\end{Example}
+
+\makeatletter
+
+% Internally, we use two "standard" arrays to define one associative array
+\newarray\AssociativeArray@Names
+\newarray\AssociativeArray@Values
+
+\newcount\AssociativeArrayNbValues
+\AssociativeArrayNbValues=\z@
+
+\newif\ifAssociativeArray@ElementFound
+
+% To store one element
+\def\AssociativeArray(#1)=#2{%
+\expandarrayelementtrue
+\AssociativeArray@ElementFoundfalse
+\edef\@tempa{#1}%
+\Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \ifx\@tempa\cachedata
+ % This element already exist: we replace it current value
+ % \checkAssociativeArray@Values(\iValue)% debug
+ % \typeout{In #1, replace `\cachedata'\space by `#2'}% Debug
+ \AssociativeArray@Values(\iValue)={#2}%
+ \AssociativeArray@ElementFoundtrue
+ \multidostop
+ \fi}
+\ifAssociativeArray@ElementFound
+\else
+ % New element
+ \advance\AssociativeArrayNbValues\@ne
+ \AssociativeArray@Names(\AssociativeArrayNbValues)={#1}%
+ \AssociativeArray@Values(\AssociativeArrayNbValues)={#2}%
+\fi}
+
+% To get one element
+\def\checkAssociativeArray(#1){%
+\edef\@tempa{#1}%
+\edef\@tempb{999999}%
+\Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \ifx\@tempa\cachedata
+ % We have found it by name
+ \edef\@tempb{\iValue}%
+ \multidostop
+ \fi}
+% We have now to get it value
+\checkAssociativeArray@Values(\@tempb)}
+
+% Simple macro to print all the associative array
+\def\printAssociativeArray{%
+\multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \iValue: \BS\texttt{FirstNames(\cachedata)}=`\AssociativeArray@Values(\iValue)'}}
+
+\makeatother
+
+\vspace{2mm}
+ Now, we can define the macros to read a sentence, to cut it letter by letter,
+to count the occurrences of each of them, and finally to draw a summary plot of
+the results.
+
+\makeatletter % Problem with the \ifpstricks conditional if not set...
+
+\ifpstricks % If PSTricks is available
+\begin{CenterExample}
+ \makeatletter
+
+ % /HLComment?A \PerChar style macro adapted from Juergen Schlegelmilch;
+ % /HLComment?(<schlegel@Informatik.Uni-Rostock.de> - posted on c.t.t. January 27, 1998);
+ /HLMacro?\def\PerChar;#1#2{\DoPerChar#1#2\@nil}
+
+ /HLMacro?\def\DoPerChar;#1#2#3\@nil{%
+ #1#2%
+ \edef\@tempa{#3}%
+ \ifx\@tempa\empty
+ \else
+ \DoPerChar#1#3\@nil
+ \fi}
+
+ % /HLComment?The action to do for each character: we increase the counter;
+ % /HLComment?for this character by one;
+ /HLMacro?\def\ActionPerChar;#1{% /HLComment?#1=character;
+ \checkAssociativeArray(#1)%
+ \ifemptydata
+ \@tempcnta=\@ne
+ \else
+ \@tempcnta=\cachedata
+ \advance\@tempcnta\@ne
+ \fi
+ \AssociativeArray(#1)={\the\@tempcnta}}
+
+ % /HLComment?To store in an associative array the number of occurrences by characters;
+ % /HLComment?(spaces are not counted);
+ /HLMacro?\def\StatSentence;#1{% /HLComment?#1=sentence;
+ \AssociativeArrayNbValues=\z@
+ \PerChar{\ActionPerChar}{#1}}
+
+ % /HLComment?To draw a plot of the number of occurrences of the characters of a sentence;
+ /HLMacro?\def\DrawOccurrences;#1{% /HLComment?#1=sentence;
+ \StatSentence{#1}
+ %
+ \pst@cnta=\AssociativeArrayNbValues
+ \advance\pst@cnta\@ne
+ %
+ % /HLComment?To know the maximum of the numbers;
+ \pst@cntb=\z@
+ \Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Values(\iValue)%
+ \ifnum\cachedata>\pst@cntb
+ \pst@cntb=\cachedata
+ \fi}
+ \advance\pst@cntb\@ne
+ %
+ % /HLComment?The drawing itself;
+ \pspicture(-0.5,-0.5)(\pst@cnta,\pst@cntb)
+ \psaxes[axesstyle=frame,labels=y](\pst@cnta,\pst@cntb)
+ \multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \Draw@OneOccurrence{\iValue}}
+ \endpspicture}
+
+ % /HLComment?To draw the value for one occurrence;
+ /HLMacro?\def\Draw@OneOccurrence;#1{% /HLComment?#1=Letter;
+ \checkAssociativeArray@Values(#1)%
+ \psdot(#1,\cachedata)
+ \rput[B](\iValue,-0.5){\AssociativeArray@Names(#1)}}
+
+ \makeatother
+
+ \let\Names\AssociativeArray
+ \let\checkNames\checkAssociativeArray
+
+ \psset{dotstyle=o,dotsize=0.4}
+
+ \DrawOccurrences{We are Wednesday}
+\end{CenterExample}
+
+\makeatletter
+
+%% A \PerChar style macro adapted from Juergen Schlegelmilch
+%% (<schlegel@Informatik.Uni-Rostock.de> - posted on c.t.t. Jan. 27, 1998)
+\def\PerChar#1#2{\DoPerChar#1#2\@nil}
+
+\def\DoPerChar#1#2#3\@nil{%
+#1#2%
+\edef\@tempa{#3}%
+\ifx\@tempa\empty
+\else
+ \DoPerChar#1#3\@nil
+\fi}
+
+% The action to do for each character: we increase the counter
+% for this character by one
+\def\ActionPerChar#1{% #1=character
+\checkAssociativeArray(#1)%
+\ifemptydata
+ \@tempcnta=\@ne
+\else
+ \@tempcnta=\cachedata
+ \advance\@tempcnta\@ne
+\fi
+\AssociativeArray(#1)={\the\@tempcnta}}
+
+% To store in an associative array the number of occurrences by characters
+% (spaces are not counted)
+\def\StatSentence#1{% #1=sentence
+\AssociativeArrayNbValues=\z@
+\PerChar{\ActionPerChar}{#1}}
+
+% To draw a plot of the number of occurrences of the characters of a sentence
+\def\DrawOccurrences#1{%
+\StatSentence{#1}
+%
+\pst@cnta=\AssociativeArrayNbValues
+\advance\pst@cnta\@ne
+%
+% To know the maximum of the numbers
+\pst@cntb=\z@
+\Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Values(\iValue)%
+ \ifnum\cachedata>\pst@cntb
+ \pst@cntb=\cachedata
+ \fi}
+\advance\pst@cntb\@ne
+%
+% The drawing itself
+\pspicture(-0.5,-0.5)(\pst@cnta,\pst@cntb)
+ \psaxes[axesstyle=frame,labels=y](\pst@cnta,\pst@cntb)
+ \multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \Draw@OneOccurrence{\iValue}}
+\endpspicture}
+
+% To draw the value for one occurrence
+\def\Draw@OneOccurrence#1{%
+\checkAssociativeArray@Values(#1)%
+\psdot(#1,\cachedata)
+\rput[B](\iValue,-0.5){\AssociativeArray@Names(#1)}}
+
+\let\Names\AssociativeArray
+\let\checkNames\checkAssociativeArray
+
+\psset{dotstyle=o,dotsize=0.4}
+
+\makeatother
+
+\vspace{8mm} % Poor hack to force a page break...
+ We will now write another version, using another array to store indexes,
+to allow us to sort the letters found in the sentence read.
+
+\begin{CenterExample}
+ \makeatletter
+
+ % /HLComment?To get in #2 the ASCII code of the #1 character;
+ /HLMacro?\def\Character@AsciiCode;#1#2{\chardef#2=`#1\relax}
+
+ % /HLComment?A new "standard" array to store the sorted indexes;
+ \newarray\AssociativeArray@Indexes
+
+ % /HLComment?A simple macro to print the array of indexes (for debugging);
+ /HLMacro?\def\PrintIndexes;{%
+ \multido{\iIndexes=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Indexes(\iIndexes)%
+ \BS\texttt{indexes(\iIndexes)}=`\cachedata'\space}}
+
+ % /HLComment?We redefine the macro to store an element in the associative array,;
+ % /HLComment?to allow to sort it elements, using an additional array of indexes;
+ /HLMacro?\def\AssociativeArray;(#1)=#2{%
+ \expandarrayelementtrue
+ \AssociativeArray@ElementFoundfalse
+ \edef\@tempa{#1}%
+ \edef\@tempb{#2}%
+ \Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \ifx\@tempa\cachedata
+ % /HLComment?This element already exist: we replace it current value;
+ % /HLComment?\checkAssociativeArray@Values(\iValue)% Debug;
+ % /HLComment?\typeout{In #1, replace `\cachedata'\space by `#2'}% Debug;
+ \AssociativeArray@Values(\iValue)={\@tempb}%
+ \AssociativeArray@ElementFoundtrue
+ \multidostop
+ \fi}
+ \ifAssociativeArray@ElementFound
+ \else
+ % /HLComment?New element: we must insert it at it sorted position;
+ \@tempcnta=\@ne
+ \expandafter\Character@AsciiCode\@tempa\@tempx
+ \Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \expandafter\Character@AsciiCode\cachedata\@tempy
+ \ifnum\@tempx<\@tempy
+ % /HLComment?The new element must be before this one: we will exchange their values;
+ \checkAssociativeArray@Indexes(\iValue)%
+ \@tempcntb=\cachedata
+ \advance\@tempcntb\@ne
+ \AssociativeArray@Indexes(\iValue)={\the\@tempcntb}%
+ \else
+ \advance\@tempcnta\@ne
+ \fi}
+ %
+ \advance\AssociativeArrayNbValues\@ne
+ \AssociativeArray@Names(\AssociativeArrayNbValues)={\@tempa}%
+ \AssociativeArray@Values(\AssociativeArrayNbValues)={\@tempb}%
+ \AssociativeArray@Indexes(\AssociativeArrayNbValues)={\the\@tempcnta}%
+ \fi}
+
+ % /HLComment?We change the way we draw each number of occurrences;
+ /HLMacro?\def\Draw@OneOccurrence;#1{%
+ \checkAssociativeArray@Indexes(#1)%
+ \pst@cnta=\cachedata
+ \checkAssociativeArray@Values(#1)%
+ \psdot(\the\pst@cnta,\cachedata)
+ \rput[B](\the\pst@cnta,-0.5){\AssociativeArray@Names(#1)}}
+
+ \makeatother
+
+ \DrawOccurrences{We are Wednesday}
+
+ \PrintIndexes
+\end{CenterExample}
+
+\makeatletter
+
+% To get in #2 the ASCII code of the #1 character
+\def\Character@AsciiCode#1#2{\chardef#2=`#1\relax}%
+
+% A new "standard" array to store the sorted indexes
+\newarray\AssociativeArray@Indexes
+
+% We redefine the macro to store an element in the associative array,
+% to allow to sort it elements, using an additional array of indexes
+\def\AssociativeArray(#1)=#2{%
+\expandarrayelementtrue
+\AssociativeArray@ElementFoundfalse
+\edef\@tempa{#1}%
+\edef\@tempb{#2}%
+\Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \ifx\@tempa\cachedata
+ % This element already exist: we replace it current value
+ % \checkAssociativeArray@Values(\iValue)% Debug
+ % \typeout{In #1, replace `\cachedata'\space by `#2'}% Debug
+ \AssociativeArray@Values(\iValue)={\@tempb}%
+ \AssociativeArray@ElementFoundtrue
+ \multidostop
+ \fi}
+\ifAssociativeArray@ElementFound
+\else
+ % New element: we must insert it at it sorted position
+ \@tempcnta=\@ne
+ \expandafter\Character@AsciiCode\@tempa\@tempx
+ \Multido{\iValue=\@ne+\@ne}{\AssociativeArrayNbValues}{%
+ \checkAssociativeArray@Names(\iValue)%
+ \expandafter\Character@AsciiCode\cachedata\@tempy
+ \ifnum\@tempx<\@tempy
+ % The new element must be before this one: we will exchange their values
+ \checkAssociativeArray@Indexes(\iValue)%
+ \@tempcntb=\cachedata
+ \advance\@tempcntb\@ne
+ \AssociativeArray@Indexes(\iValue)={\the\@tempcntb}%
+ \else
+ \advance\@tempcnta\@ne
+ \fi}
+ %
+ \advance\AssociativeArrayNbValues\@ne
+ \AssociativeArray@Names(\AssociativeArrayNbValues)={\@tempa}%
+ \AssociativeArray@Values(\AssociativeArrayNbValues)={\@tempb}%
+ \AssociativeArray@Indexes(\AssociativeArrayNbValues)={\the\@tempcnta}%
+\fi}
+
+% We change the way we draw each number of occurrences
+\def\Draw@OneOccurrence#1{%
+\checkAssociativeArray@Indexes(#1)%
+\pst@cnta=\cachedata
+\checkAssociativeArray@Values(#1)%
+\psdot(\the\pst@cnta,\cachedata)
+\rput[B](\the\pst@cnta,-0.5){\AssociativeArray@Names(#1)}}
+
+\makeatother
+
+\begin{CenterExample}
+ \DrawOccurrences{Tuesday 8 February}
+\end{CenterExample}
+
+\noindent Now, we can easily redefine the internal macro which plot each
+occurrence, to obtain various kinds of graphics:
+
+\begin{CenterExample}
+ \makeatletter
+
+ /HLMacro?\def\Draw@OneOccurrence;#1{%
+ \checkAssociativeArray@Indexes(#1)%
+ \pst@cnta=\cachedata
+ \checkAssociativeArray@Values(#1)
+ \psline[linestyle=dotted](\the\pst@cnta,0)(\the\pst@cnta,\cachedata)
+ \psdot(\the\pst@cnta,\cachedata)
+ \rput[B](\the\pst@cnta,-0.5){\AssociativeArray@Names(#1)}}
+
+ \makeatother
+
+ \psset{xunit=0.5,dotstyle=*,dotsize=0.3}
+ \DrawOccurrences{I do not believe that it can be correct}
+\end{CenterExample}
+
+\begin{CenterExample}
+ \makeatletter
+
+ \SpecialCoor
+
+ /HLMacro?\def\Draw@OneOccurrence;#1{%
+ \checkAssociativeArray@Indexes(#1)%
+ \pst@cnta=\cachedata
+ \checkAssociativeArray@Values(#1)%
+ \pspolygon*[linecolor=red](! \the\pst@cnta\space 0.3 sub 0)
+ (! \the\pst@cnta\space 0.3 sub \cachedata)
+ (! \the\pst@cnta\space 0.3 add \cachedata)
+ (! \the\pst@cnta\space 0.3 add 0)
+ \rput[B](\the\pst@cnta,-0.5){\AssociativeArray@Names(#1)}}
+
+ \makeatother
+
+ \psset{xunit=0.5,ticks=y}
+ \DrawOccurrences{I don't know a better solution than this one}
+\end{CenterExample}
+\else
+ \PSTricksExampleNotShown
+\fi % End \pstrickstrue
+
+\section{Thanks}
+
+ I would like to thank Rolf Niepraschk \verb+<niepraschk@ptb.de>+ to have
+carefully read a preliminary version of this document and to have sent me
+several good advices to clarify and improve some points.
+
+\begin{thebibliography}{9}
+ \bibitem{SVB93} Stephan von \textsc{Bechtolsheim}, \emph{\TeX{} in
+ Practice}, four volumes, Springer-Verlag, New York, 1993 (see also
+ \url{CTAN: macros/tip/arraymac.tip}).
+ \bibitem{REPEAT} \RepeatPackage, by Victor \textsc{Eijkhout}, University of
+ Illinois, Urbana-Champaign, USA, \url{CTAN: macros/generic/eijkhout/repeat}
+ \bibitem{EG98} Philippe \textsc{Esperet} and Denis \textsc{Girou},
+ \emph{Coloriage du pavage dit de Truchet}, Cahiers GUTenberg, Number~31,
+ December 98, pages 5-18, in french (see
+ \url{http://www.gutenberg.eu.org/pub/GUTenberg/publicationsPS/31-girou.ps.gz}).
+ \bibitem{ALDRATEX} \AlDraTeXPackage, by Eitan M. \textsc{Gurari}, Ohio State
+ University, Columbus, USA, \url{CTAN: graphics/dratex} (see also
+ \url{http://www.cis.ohio-state.edu/~gurari/systems.html}).
+ \bibitem{Gur94} Eitan M. \textsc{Gurari}, \emph{\TeX{} and \LaTeX: Drawing
+ and Literate Programming}, McGraw-Hill, New-York, 1994.
+ \bibitem{METAPOST} \MetaPostPackage, by John D. \textsc{Hobby}, AT\&T Bell
+ Laboratories, USA, \url{CTAN: graphics/metapost} (see also
+ \url{http://cm.bell-labs.com/who/hobby/MetaPost.html}).
+ \bibitem{FORMLETT} \FormLettPackage, by Zhuhan \textsc{Jiang}, University of
+ New England, Armidale, Australia, \url{CTAN: macros/generic/formlett.sty} (see
+ also \url{http://maths.une.edu.au/~zhuhan/util.html#computer}).
+ \bibitem{MULTIDO} \MultiDoPackage, by Timothy van \textsc{Zandt}, INSEAD,
+ Fontainebleau, France, \url{CTAN: macros/generic/multido}
+ \bibitem{PSTRICKS} \PSTricksPackage, by Timothy van \textsc{Zandt}, INSEAD,
+ Fontainebleau, France, \url{CTAN: graphics/pstricks} (see also
+ \url{http://www.tug.org/applications/PSTricks}).
+\end{thebibliography}
+
+\end{document}