5
\documentclass[a4paper,10pt]{article}
\usepackage{arrayjob}
\begin{document}
\newarray\cws
\cws(0)=3pt
\cws(1)=4pt
\let\a\dimexpr\cws(0)+\cws(1)\relax
\a
\end{document}

Error: ! You can't use `\dimexpr' in horizontal mode.

This doesn't work either:

\let\a\z@
\advance\a\cws(0)
\advance\a\cws(1)
\a

How can I create a sum of elements in an array (arrayjob)?

nagylzs
  • 1,225

4 Answers4

6

That's a job for expl3!

\documentclass{article}
\pagestyle{empty}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \l_nagylzs_cws_seq

\NewDocumentCommand \ArraySet { m }
 {
  \seq_set_from_clist:Nn \l_nagylzs_cws_seq { #1 }
 }

\NewDocumentCommand \ArraySum { m }
 {
  \dim_zero:N \l_tmpa_dim
  \seq_map_inline:Nn \l_nagylzs_cws_seq
  {
   \dim_add:Nn \l_tmpa_dim { ##1 }
  }
  #1 = \l_tmpa_dim
}
\ExplSyntaxOff
\begin{document}
\ArraySet{3pt,4pt,4ex,1in}
\ArraySum{\dimen0}
\the\dimen0
\end{document}

enter image description here


Here is a completely unreadable version of the above code violating all expl3 standards but sort of fulfilling the least-lines-criterium.

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\def\ArraySet#1{\seq_set_from_clist:Nn\cws{#1}}
\def\ArraySum#1{\dim_zero:N\l_tmpa_dim
  \seq_map_inline:Nn\cws{\dim_add:Nn\l_tmpa_dim{##1}}
  #1=\l_tmpa_dim}
\ExplSyntaxOff
\begin{document}
\ArraySet{3pt,4pt,4ex,1in}
\ArraySum{\dimen0}
\the\dimen0
\end{document}
Manuel
  • 27,118
Henri Menke
  • 109,596
3

First of all you should use arrayjobx and not arrayjob (the latter is not really compatible with LaTeX).

Secondly, \let\a\dimexpr will make \a equivalent to \dimexpr and try printing \cws(0)+\cws(1)\relax; then \a will produce an error just like

\dimexpr
\end{document}

You should use \newcommand and not \let, but it won't do anyway, because \cws(0) is not good inside `\dimexpr, as it requires assignments that are not performed in that context.

Here's a different implementation using expl3 and its property lists.

\documentclass[a4paper,10pt]{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\DeclareArray}{m}
 {
  \prop_new:c { l_nagylzs_array_#1_prop }
  \cs_new:cpn { #1 } ##1 { \prop_item:cn { l_nagylzs_array_#1_prop } { ##1 } }
 }
\NewDocumentCommand{\setarray}{mmm}
 {
  \prop_put:cnn { l_nagylzs_array_#1_prop } { #2 } { #3 }
 }
\ExplSyntaxOff


\begin{document}
\DeclareArray{cws}
\setarray{cws}{0}{3pt}
\setarray{cws}{1}{4pt}
\setarray{cws}{2}{1in}

\newcommand\foo{\dimexpr\cws{0}+\cws{1}+\cws{2}\relax}

A\hspace{\foo}B

A\hspace{\dimexpr\cws{0}+\cws{1}\relax}B

A\hspace{\dimexpr\cws{0}\relax}B

\end{document}

enter image description here

A package free version, that however is less flexible.

\documentclass[a4paper,10pt]{article}

\makeatletter
\newcommand\newarray[1]{%
  \newcommand{#1}[1]{\@nameuse{nagylzs@\string#1@##1}}%
}
\newcommand{\set}[3]{\@namedef{nagylzs@\string#1@#2}{#3}}
\makeatother

\begin{document}
\newarray{\cws}
\set\cws{0}{3pt}
\set\cws{1}{4pt}
\set\cws{2}{1in}

\newcommand\foo{\dimexpr\cws{0}+\cws{1}+\cws{2}\relax}

A\hspace{\foo}B

A\hspace{\dimexpr\cws{0}+\cws{1}\relax}B

A\hspace{\dimexpr\cws{0}\relax}B

\end{document}

Explanation. There is no array data type in TeX, so one has to build it. This implementation uses \csname which provides a kind of associative memory.

Defining an array simply defines a command for using the values stored with \set. The command \cws{0} expands to

\@nameuse{nagylzs@\string\cws@0}

that's the same as

\csname nagylzs@\string\cws@0\endcsname

Note that \cws is “stringified”, so it can appear in \csname...\endcsname. The \set command does the association: \set\cws{0}{3pt} does

\@namedef{nagylzs@\string\cws@0}{4pt}

which is the same as

\expandafter\def\csname nagylzs@\string\cws@0\endcsname{4pt}

The association is thus in the name of a macro. The macro name is complicated in order to avoid collisions with other macros.

egreg
  • 1,121,712
3

The array notation isn't really helping, especially as implemented in your question where it is not expandable so can not be used in lots of places, such as \dimexpr.

here is an expandable version:

enter image description here

\documentclass[a4paper,10pt]{article}

\def\set#1#2#3{\expandafter\def\csname#1#2\endcsname{#3}}
\def\use#1#2{\csname#1#2\endcsname}
\begin{document}

\set{cws}{0}{3pt}
\set{cws}{1}{4pt}


\the\dimexpr\use{cws}{0}+\use{cws}{1}\relax


\end{document}
David Carlisle
  • 757,742
  • This is the only one I could understand so far without reading some hundred pages of documentation of experimental packages. :-) – nagylzs Oct 24 '14 at 18:00
1

EDITED: Here's a different approach using the listofitems package. EDITED to demonstrate functionality with different unit sets in the array.

\documentclass[a4paper,10pt]{article}
\usepackage{listofitems}
\setsepchar{ }
\begin{document}
\def\data{3pt 4ex 1in}% space separated data
\readlist\cws{\data}% reads \data into list named "cws" 

A\hspace{\dimexpr\cws[1]+\cws[2]+\cws[3]}B

A\hspace{\dimexpr\cws[1]+\cws[2]}B

A\hspace{\dimexpr\cws[1]}B
\end{document}

enter image description here