Create an array of variables
You can define a macro which name contains numbers. Use LaTeX2e's \@namedef
and \@nameuse
, or \csdef
, \csuse
from etoolbox
package. And etoolbox
itself provides list operations without index.
An example:
\documentclass{article}
\usepackage{etoolbox}
\newcounter{cnt}
\newcommand\textlist{}
\newcommand\settext[2]{%
\csdef{text#1}{#2}}
\newcommand\addtext[1]{%
\stepcounter{cnt}%
\csdef{text\thecnt}{#1}}
\newcommand\gettext[1]{%
\csuse{text#1}}
\newcounter{colnum}
\newcommand\maketabularrow[1]{%
\setcounter{colnum}{0}%
\whileboolexpr
{ test {\ifnumcomp{\value{colnum}}{<}{#1}} }%
{&\stepcounter{colnum}\thecolnum}
}
\begin{document}
\addtext{one}
\addtext{two}
\addtext{three}
\settext{100}{one hundred}
This is text \gettext{1} and \gettext{3}, that is text \gettext{2}.
\begin{tabular}{ |c@{} *{\thecnt}{c|} } % the first row is hidden
\hline
\maketabularrow{\thecnt}\\ \hline
\end{tabular}
100 is \gettext{100}.
\end{document}
You have two questions that I can see. First, you want to know how to create an associative (programming) array mapping questions to their points. And second, you want to know how to create a (LaTeX table) array that prints these. As I usually do, I recommend using pgfkeys
as your programming language here, particularly (in this case) because as a key-value package, its entire life is devoted to constructing associative arrays.
Here's how I'd create your array of points:
\usepackage{pgfkeys}
\pgfkeys{
/points array/.is family, /points array,
.unknown/.style = {\pgfkeyscurrentname/.initial = #1},
}
\newcommand\questionhaspoints[1]{\pgfkeys{/points array, #1}}
\newcommand\getquestionpoints[1]{\pgfkeysvalueof{/points array/#1}}
You can then write, say, \questionhaspoints{1 = 10, 2 = 5}
to say that question 1 has 10 points and question 2 has 5 points. If you want to retrieve these, you just call \getquestionpoints{1}
and \getquestionpoints{2}
.
The \pgfkeys
invocation sets up the family /points array
so that any time you try to assign a new key in it (one that is "unknown" as of yet) it is simply filled with the value you requested. pgfkeys
can do lots of stuff with keys other than just store their values, as you will see in a second.
To construct the LaTeX array, I think it is necessary to loop and construct the rows before calling \begin{tabular}
, since in TeX, alignments are very particular about what can appear where in them, in particular the &
and \\
directives. It's best for everything to look "right" before starting the table.
Here is my code for constructing the table:
\usepackage{pgffor}
\pgfkeys{
/points array,
add to table/.style = {
table/.append = {
Question #1
&
\getquestionpoints{#1}
\\
},
},
}
\newcommand\makepointstable[1]{%
\pgfkeys{
/points array,
table/.initial = {},
add to table/.list = {1,...,#1}
}%
}
The new key /points array/add to table
just tacks its argument onto a key called table
(presumed to be in /points array
too). It is used in the loop that is implied by the construction add to table/.list = {<list of question numbers>}
, which performs a loop over the numbers in its argument, calling add to table
with that number each time. The result is that the table
key holds the body of the array. Now you can put that in a {tabular}
. Here is a complete document that does that:
\documentclass{article}
\usepackage{pgfkeys,pgffor}
\pgfkeys{
/points array/.is family, /points array,
.unknown/.style = {\pgfkeyscurrentname/.initial = #1},
add to table/.style = {
table/.append = {
Question #1
&
\getquestionpoints{#1}
\\
},
},
}
\newcommand\questionhaspoints[1]{\pgfkeys{/points array, #1}}
\newcommand\getquestionpoints[1]{\pgfkeysvalueof{/points array/#1}}
\newcommand\makepointstable[1]{%
\pgfkeys{
/points array,
table/.initial = {},
add to table/.list = {1,...,#1}
}%
}
\begin{document}
\questionhaspoints{1 = 10, 2 = 8, 3 = 15, 4 = 10}
\makepointstable{4}
\begin{tabular}{l|r}
\pgfkeysvalueof{/points array/table}
\end{tabular}
\end{document}
The latest version of etoolbox provides lists and their management options. Here is the solution for any one interested.
The below code demonstrates how easy it is now to create and iterate over a list of variables.
\documentclass{article}
\RequirePackage{etoolbox} % defines lists and their operations
\RequirePackage{tabulary} % defines content-based sizable tables
\begin{document}
% define few variables that hold some value
\def\One{this is one}
\def\Two{this is two}
\def\Three{this is three}
% add the above commands to a list named `CmdList'
\listcsgadd{CmdList}{One}
\listcsgadd{CmdList}{Two}
\listcsgadd{CmdList}{Three}
% Now loop-over them to print their values
\begin{description}
\renewcommand*{\do}[1]{\item[#1:] \csuse{#1}}
\dolistcsloop{CmdList}
\end{description}
% creating a table needs little bit more trickery; You cannot insert table entries directly.
% You first have to accumulate all table data into some temporary variable and then use that.
\begingroup
\newcommand\tablecontent{}
\def\do#1{\appto\tablecontent{\hline \textbf{#1} & \csuse{#1}\\}}%
\dolistcsloop{CmdList} % collect the data in a table format
\begin{tabulary}{\textwidth}{|L|L|} % now print the collected data
\tablecontent \hline
\end{tabulary}
\endgroup
\end{document}