\documentclass{standalone}
\usepackage{readarray}
\def\data{%
1 15 14 4
10 11 8 5
7 6 9 12
16 2 3 13
}
\readarray\data\dataA[4,4]
\begin{document}
value at (2,1) = \dataA[2,1]
\expandafter\def\csname dataA[2,1]\endcsname{42}
value at (2,1) = \dataA[2,1]
\end{document}

While this may seem like its "cheating", this is in fact the way the package defines array element names:
\def\arg@name{\csname#3[\the@row,\the@col]\endcsname}%
If you wanted a pretty looking macro, I define here \setvalue. Not done here, but one could do bounds-checking as part of the macro.
\documentclass{standalone}
\usepackage{readarray}
\makeatletter
\def\setvalue#1[#2]#3{%
\expandafter\def\csname
\expandafter\@gobble\string#1[#2]\endcsname{#3}%
}
\makeatother
\def\data{%
1 15 14 4
10 11 8 5
7 6 9 12
16 2 3 13
}
\readarray\data\dataA[4,4]
\begin{document}
value at (2,1) = \dataA[2,1]
\setvalue\dataA[2,1]{42}
value at (2,1) = \dataA[2,1]
\end{document}
LONG OVERDUE SUPPLEMENT
Two years ago, I promised the OP to eventually make revisions to the readarray package to initialize and extend arrays. I was again reminded recently that I had not done it.
I can't say that what follows will be the final version that gets into a package revision, but it presents the flavor of what I have in mind (certainly, some of the internal macros will be named less generically).
First, I have a file, readarrayhotmod.tex, that one can \input into their document:
\RequirePackage{pgffor}
\newcount\readarrayendlinechar
% INITIALIATIONS
% ON \readdef, SEP CHAR INSERTED AFTER EACH RECORD;
% ON \readarray, SEP CHAR SERVES AS DATA-FIELD SEPARATOR
\readarraysepchar{ }
% ON \readdef, IGNORE END-LINE CHARS BY DEFAULT (NORMAL LaTeX MODE = 5)
\readarrayendlinechar=9
% DEFAULT CELL DATA FOR \initarray
\def\readarrayinitvalue{-}
% DEFAULT FIELD SEPARATORS FOR \typesetarray
\def\readarrayplanesep{\\---\\}
\def\readarrayrowsep{\\}
\def\readarraycolsep{,}
% DEFAULT CELL FORMATTING ON \typesetarray
\def\readarraycellset#1{#1}
%
\makeatletter
% FIXES ON EXISTING MACROS
\def\define@rootmacro#1{%
\expandafter\def\csname#1\endcsname[##1]{\rootmacro@aux{#1}{##1}}%
}
%
\def\nocheckbounds{\def\rootmacro@aux##1##2{\csname##1[##2]\endcsname%
}\typeout{readarray: bounds checking OFF}%
}
%
\def\checkbounds{\def\rootmacro@aux##1##2{%
\ifcsname##1[##2]\endcsname\csname##1[##2]\endcsname\else%
\readarrayboundfailmsg%
\typeout{readarray Warning: \RAbackslash##1[##2] undefined.}%
\fi%
}\typeout{readarray: bounds checking ON}%
}
%
\def\hypercheckbounds{\def\rootmacro@aux##1##2{%
\ifcsname##1[##2]\endcsname\csname##1[##2]\endcsname\else
\readarrayboundfailmsg%
\typeout{readarray Warning: \RAbackslash##1[##2] undefined:}%
\setcounter{index@count}{0}%
\parse@index##2,\relax%
\foreach\i in{1,...,\theindex@count}{%
\ifnum\parsed@index[\i]<1%
\relax\typeout{\nonposmessage{##1}{##2}}\fi%
}%
\ifnum \value{index@count}=1\relax%
\ifnum\parsed@index[1]>\csname##1CELLS\endcsname\relax
\typeout{\recordmessage{##1}{##2}}\fi%
\fi
\ifnum \value{index@count}=2\relax%
\ifnum\parsed@index[1]>\csname##1ROWS\endcsname\relax
\typeout{\rowmessage{##1}{\parsed@index[1]}}\fi%
\ifnum\parsed@index[2]>\csname##1COLS\endcsname\relax
\typeout{\colmessage{##1}{\parsed@index[2]}}\fi%
\fi
\ifnum \value{index@count}=3\relax%
\ifnum\parsed@index[1]>\csname##1PLANES\endcsname\relax
\typeout{\planemessage{##1}{\parsed@index[1]}}\fi%
\ifnum\parsed@index[2]>\csname##1ROWS\endcsname\relax
\typeout{\rowmessage{##1}{\parsed@index[2]}}\fi%
\ifnum\parsed@index[3]>\csname##1COLS\endcsname\relax
\typeout{\colmessage{##1}{\parsed@index[3]}}\fi%
\fi%
\fi%
}\typeout{readarray: bounds hyperchecking ON}%
}
%
\def\@readdef#1#2#3{%
\clear@array{#3}%
\edef\former@recordcount{\csname #3CELLS\endcsname}%
\def\first@row{T}%
\def\first@plane{T}%
\catcode\endlinechar=\readarrayendlinechar\relax %
\def#2{}%
\setcounter{@record}{0}%
\openin\rdar@file=#1%
\loop\unless\ifeof\rdar@file%
\read\rdar@file to\rdar@fileline % Reads a line of the file into \rdar@fileline%
\addtocounter{@record}{1}%
\expandafter\g@addto@macro\expandafter#2\expandafter{\rdar@fileline}%
\ifthenelse{\equal{\rdar@fileline}{}}{}{\expandafter\g@addto@macro%
\expandafter#2\expandafter{\read@array@sepchar}}%
\if T\first@row\read@array{#2}\setcounter{@col}{\numexpr(\Arg@listlen-1)}%
\edef\ncols{\arabic{@col}}\def\first@row{F}\setcounter{@row}{1}%
\else%
\if T\first@plane%
\ifthenelse{\equal{\rdar@fileline}{}}{%
\edef\nrows{\arabic{@row}}\def\first@plane{F}%
}{%
\addtocounter{@row}{1}%
}%
\fi%
\fi%
\def\record@name{\csname #3[\the@record]\endcsname}%
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter%
\expandafter\def\expandafter\record@name\expandafter{\rdar@fileline}%
\repeat%
\edef\nrecords{\arabic{@record}}%
\expandafter\edef\csname #3PLANES\endcsname{0}%
\expandafter\edef\csname #3ROWS\endcsname{\nrecords}%
\expandafter\edef\csname #3COLS\endcsname{0}%
\expandafter\edef\csname #3CELLS\endcsname{\nrecords}%
\closein\rdar@file%
\catcode\endlinechar=5 %
\define@rootmacro{#3}%
}
%
\def\clear@array#1{%
\ifcsname #1\endcsname%
\setcounter{@row}{0}%
\whiledo{\value{@row}<\csname #1ROWS\endcsname}{%
\stepcounter{@row}%
\ifnum\csname #1COLS\endcsname=0\relax%
\expandafter\let\csname #1[\the@row]\endcsname\undefined%
\else
\setcounter{@col}{0}%
\whiledo{\value{@col}<\csname #1COLS\endcsname}{%
\stepcounter{@col}%
\ifnum\csname #1PLANES\endcsname=0\relax%
\expandafter\let\csname #1[\the@row,\the@col]\endcsname
\undefined%
\else
\setcounter{@plane}{0}%
\whiledo{\value{@plane}<\csname #1PLANES\endcsname}{%
\stepcounter{@plane}%
\expandafter%
\let\csname #1[\the@plane,\the@row,\the@col]\endcsname
\undefined%
}%
\fi%
}%
\fi%
}%
\expandafter\let\csname #1PLANES\endcsname\undefined
\expandafter\let\csname #1ROWS\endcsname\undefined
\expandafter\let\csname #1PLANES\endcsname\undefined
\expandafter\let\csname #1\endcsname\undefined
\fi%
}
%
\def\nonposmessage#1#2{Positive indices [#2] required for #1.}
%%% END FIXES
%
\def\parsed@index[#1]{\csname parsed@index[#1]\endcsname}
%
\edef\RAbackslash{\expandafter\@firstoftwo\string\\}
%
\def\setvalue#1[#2]#3{%
\ifcsname\rdar@macroname#1[#2]\endcsname
\expandafter\gdef\csname\rdar@macroname#1[#2]\endcsname{#3}%
\else
\typeout{readarray Warning (setvalue = #3):
\RAbackslash\rdar@macroname#1[#2] undefined.}%
\fi%
}
\def\RAinitializedata#1[#2]#3{%
\expandafter\gdef\csname
\rdar@macroname#1[#2]\expandafter\endcsname\expandafter{#3}%
}
%
\def\initarray#1[#2]{%
\clear@array{\rdar@macroname#1}%
\expandafter\define@rootmacro\expandafter{\rdar@macroname#1}%
\setcounter{index@count}{0}%
\parse@index#2,\relax
\ifnum\value{index@count}=2\relax
\setcounter{use@args}{\numexpr\parsed@index[1]*\parsed@index[2]}
\expandafter\def\csname\rdar@macroname
#1PLANES\endcsname{0}
\expandafter\edef\csname\rdar@macroname
#1ROWS\endcsname{\parsed@index[1]}
\expandafter\edef\csname\rdar@macroname
#1COLS\endcsname{\parsed@index[2]}
\expandafter\edef\csname\rdar@macroname
#1CELLS\endcsname{\theuse@args}
\foreach\Z in{1,...,\parsed@index[1]}{%
\foreach\ZZ in{1,...,\parsed@index[2]}{%
\RAinitializedata#1[\Z,\ZZ]{\readarrayinitvalue}}}
\else
\ifnum\value{index@count}=3\relax
\setcounter{use@args}{\numexpr\parsed@index[1]*
\parsed@index[2]*\parsed@index[3]}
\expandafter\edef\csname\rdar@macroname
#1PLANES\endcsname{\parsed@index[1]}
\expandafter\edef\csname\rdar@macroname
#1ROWS\endcsname{\parsed@index[2]}
\expandafter\edef\csname\rdar@macroname
#1COLS\endcsname{\parsed@index[3]}
\expandafter\edef\csname\rdar@macroname
#1CELLS\endcsname{\theuse@args}
\foreach\Z in{1,...,\parsed@index[1]}{%
\foreach\ZZ in{1,...,\parsed@index[2]}{%
\foreach\ZZZ in{1,...,\parsed@index[3]}{%
\RAinitializedata#1[\Z,\ZZ,\ZZZ]{\readarrayinitvalue}}}}
\else
[initarray ERROR: 2-D or 3-D arrays only]
\fi
\fi
}
%
\def\mergearray#1#2[#3]{%
\setcounter{index@count}{0}%
\parse@index#3,\relax
\ifnum\value{index@count}=2\relax
\foreach\Z in{1,...,\csname\rdar@macroname#1ROWS\endcsname}{%
\foreach\ZZ in{1,...,\csname\rdar@macroname#1COLS\endcsname}{%
\edef\tmpA{\the\numexpr\Z+\parsed@index[1]-1,%
\the\numexpr\ZZ+\parsed@index[2]-1 }%
\edef\tmpB{\csname\rdar@macroname#1[\Z,\ZZ]\endcsname}%
\def\tmpC{\setvalue#2[\tmpA]}%
\expandafter\tmpC\expandafter{\tmpB}}}%
\else
\ifnum\value{index@count}=3\relax
\foreach\Z in{1,...,\csname\rdar@macroname#1PLANES\endcsname}{%
\foreach\ZZ in{1,...,\csname\rdar@macroname#1ROWS\endcsname}{%
\foreach\ZZZ in{1,...,\csname\rdar@macroname#1COLS\endcsname}{%
\edef\tmpA{\the\numexpr\Z+\parsed@index[1]-1,%
\the\numexpr\ZZ+\parsed@index[2]-1,%
\the\numexpr\ZZZ+\parsed@index[3]-1 }%
\edef\tmpB{\csname\rdar@macroname#1[\Z,\ZZ,\ZZZ]\endcsname}%
\def\tmpC{\setvalue#2[\tmpA]}%
\expandafter\tmpC\expandafter{\tmpB}}}}%
\else
[mergearray ERROR: 2-D or 3-D arrays only]
\fi
\fi
}
%
\def\addtoArg@toks#1{\global\Arg@toks\expandafter{\the\Arg@toks#1}}
\def\xaddtoArg@toks#1{\expandafter\addtoArg@toks\expandafter{#1}}
\def\xxaddtoArg@toks#1{\expandafter\xaddtoArg@toks\expandafter{#1}}
%
\def\typesetarray#1{\noindent\Arg@toks{}%
\ifnum\csname\rdar@macroname#1PLANES\endcsname>0\relax
\foreach\Z in{1,...,\csname\rdar@macroname#1PLANES\endcsname}{%
\ifnum\Z=1 \else\xaddtoArg@toks{\readarrayplanesep}\fi%
\foreach\ZZ in{1,...,\csname\rdar@macroname#1ROWS\endcsname}{%
\ifnum\ZZ=1 \else\xaddtoArg@toks{\readarrayrowsep}\fi%
\foreach\ZZZ in{1,...,\csname\rdar@macroname#1COLS\endcsname}{%
\ifnum\ZZZ=1 \else\xaddtoArg@toks{\readarraycolsep}\fi%
\xxaddtoArg@toks{\expandafter\readarraycellset\expandafter
{\csname\rdar@macroname#1[\Z,\ZZ,\ZZZ]\endcsname}}}%
}%
}%
\else
\foreach\Z in{1,...,\csname\rdar@macroname#1ROWS\endcsname}{%
\ifnum\Z=1 \else\xaddtoArg@toks{\readarrayrowsep}\fi%
\foreach\ZZ in{1,...,\csname\rdar@macroname#1COLS\endcsname}{%
\ifnum\ZZ=1 \else\xaddtoArg@toks{\readarraycolsep}\fi%
\xxaddtoArg@toks{\expandafter\readarraycellset\expandafter
{\csname\rdar@macroname#1[\Z,\ZZ]\endcsname}}%
}%
}%
\fi
\the\Arg@toks
}
\makeatother
In addition to providing error checking on \setvalue which was provided in the answer above, it introduces 3 new commands:
\initarray\<arrayname>[<2-D or 3-D size>]
\mergearray\<from-array>\<to-array>[<insert point]
\typeset\<arrayname>
Examples would include \initarray\AB[6,6] to initialize a 6x6 array, each cell containing the replacement text of \arrayinitvalue. A merge example would be \mergearray\dataA\AB[3,2] which would merge the dataA array into the \AB array, beginning at cell [3,2] in \AB. So if \dataA is 4x4, it would span from \AB[3,2]--\AB[6,5]. If the merge extends past the \AB array boundary, warnings are printed in the log file (and at present, the document itself). The command \typesetarray\AB would output the \AB array, employing the follow default, but changeable settings:
\def\arrayplnsep{\\---\\}
\def\arrayrowsep{\\}
\def\arraycolsep{,}
\def\arrayset#1{#1}
These settings tell what gets typeset between planes, rows, columns, and how to typeset the cell itself. Changing \arraycolsep to & will make the typeset suitable for a tabular environment, for example. If you wish to typeset directly, then \def\arrayset#1{\makebox[5ex][r]{#1}} will allow a fixed space to be allocated for the typesetting of each cell.
\documentclass{article}
\usepackage{readarray}
\input readarrayhotmod.tex
% DEFAULTS
%% INITIALIATIONS
%% ON \readdef, SEP CHAR INSERTED AFTER EACH RECORD;
%% ON \readarray, SEP CHAR SERVES AS DATA-FIELD SEPARATOR
% \readarraysepchar{ }
%% ON \readdef, IGNORE END-LINE CHARS BY DEFAULT (NORMAL LaTeX MODE = 5)
% \readarrayendlinechar=9
%% DEFAULT CELL DATA FOR \initarray
% \def\readarrayinitvalue{-}
%% DEFAULT FIELD SEPARATORS FOR \typesetarray
% \def\readarrayplanesep{\---\}
% \def\readarrayrowsep{\}
% \def\readarraycolsep{,}
%% DEFAULT CELL FORMATTING ON \typesetarray
% \def\readarraycellset#1{#1}
%%
\begin{filecontents}[overwrite]{mydata.txt}
1,15,14,4
10,11,8,5
7,6,9,12
16,2,3,13
\end{filecontents}
\begin{document}
\sbox0{\begin{tabular}{|c|}\hline x\end{tabular}}% LOADS cmex FONTS
\hypercheckbounds
\readarraysepchar{,}
\readdef{mydata.txt}\data
- Set value in bounds and out of bounds\hrulefill
\readarray\data\dataA[-,\ncols]
value at (2,1) = \dataA[2,1]
\setvalue\dataA[2,1]{42}
value at (2,1) = \dataA[2,1]
\setvalue\dataA[2,7]{42}
- Initialize 6x6 array, specify in and out of bound cells\hrulefill
\initarray\AB[6,6]
AB[2,1] = \AB[2,1]
AB[2,2] = \AB[2,2]
AB[3,7] = \AB[3,7]
- Merge 4x4 array into 6x6, typeset as text and in tabular\hrulefill
\mergearray\dataA\AB[3,2]
\def\readarrayrowsep{\}
\def\readarraycolsep{,}
\def\readarraycellset#1{\makebox[5ex][r]{#1}}
\typesetarray\AB
\def\readarrayrowsep{\}
\def\readarraycolsep{&}
\def\readarraycellset#1{#1}
tabular: \begin{tabular}{cc|cccc}
\hline
\typesetarray\AB
\\hline
\end{tabular}
- Initialize 3x5x4 (3-D) array, set value\hrulefill
\renewcommand\readarrayinitvalue{Q}
\initarray\Q[3,5,4]
\Q[3,4,2]
\setvalue\Q[3,4,2]{SV}
\Q[3,4,2]
- Merge initialized 2x2x2 AND read-in 2x2x4 arrays into 3x5x4 array\hrulefill
\renewcommand\readarrayinitvalue{R}
\initarray\R[2,2,2]
\readarray\data\dataB[-,2,4]
\mergearray\dataB\Q[1,4,1]
\mergearray\R\Q[2,2,1]
\def\readarrayplanesep{\\hline}
\def\readarrayrowsep{\}
\def\readarraycolsep{&}
\def\readarraycellset#1{#1}
\begin{tabular}{rrrrr}
\hline
\typesetarray\Q
\\hline
\end{tabular}
- Error checking when existing array is reinitialized\hrulefill
\initarray\Q[2,2]
\Q[0,2,2] \Q[1,2,2] \QPLANES
\end{document}
This code produces the following warnings in the log file
readarray: bounds hyperchecking ON
readarray Warning (setvalue = 42): \dataA[2,7] undefined.
readarray Warning: \AB[3,7] undefined:
COL=7 exceeds bounds(=6) for AB.
readarray Warning: \Q[0,2,2] undefined:
Positive indices [0,2,2] required for Q.
readarray Warning: \Q[1,2,2] undefined:
PLANE=1 exceeds bounds(=0) for Q.
and this output

\expandafter\def\csname dataA[5,1]\endcsname{3}what is actually index out of bounds, but it works. i even can get the values of\dataA[5,1]. is there a regular way to add new rows/columns? – susis strolch Jun 30 '19 at 01:15\defindeed provides no bounds checking. Allowing rows/columns to be added would make the bookkeeping more difficult. p.s. I provide a\setvaluemacro. – Steven B. Segletes Jun 30 '19 at 01:27\<arrayidentifier>CELLS,\<arrayidentifier>ROWS, and\<arrayidentifier>COLS(and\<arrayidentifier>PLANESin 3-D), and also initializing the newly created cells as empty. – Steven B. Segletes Jun 30 '19 at 01:38\emptyarray\dataA[10,100]would be an nice extension. same for an easy\writedef{filename}\dataA... if you allow me to mention some feature request here. – susis strolch Jun 30 '19 at 03:22