在 readray 中设置值

在 readray 中设置值

我确实喜欢 readarray 包的简单性,但是有没有办法设置/更改 readarray 生成的数据结构中的值?

\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]

%what i'm searching for: 
%\set\dataA[2,1]{42} 

\end{document}

答案1

\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}

在此处输入图片描述

虽然这看起来像是“作弊”,但实际上这是包定义数组元素名称的方式:

\def\arg@name{\csname#3[\the@row,\the@col]\endcsname}%

如果你想要一个好看的宏,我在这里定义\setvalue。这里没有完成,但可以将边界检查作为宏的一部分。

\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}

姗姗来迟的补充

两年前,我向楼主承诺最终对包进行修改readarray以初始化和扩展数组。最近我再次被提醒我还没有这样做。

我不能说接下来的内容将是进入软件包修订的最终版本,但是它呈现了我心中的想法(当然,一些内部宏的命名将不那么通用)。

首先,我有一个文件readarrayhotmod.tex,可以将其\input放入他们的文档中:

\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

除了提供\setvalue上述答案中提供的错误检查之外,它还引入了 3 个新命令:

\initarray\<arrayname>[<2-D or 3-D size>]
\mergearray\<from-array>\<to-array>[<insert point]
\typeset\<arrayname>

示例包括\initarray\AB[6,6]初始化一个 6x6 数组,每个单元格包含 的替换文本\arrayinitvalue。合并示例是\mergearray\dataA\AB[3,2]dataA数组合并到 数组中,从中的\AB单元格开始。因此,如果是 4x4,它将跨越-- 。如果合并超出数组边界,则会在日志文件(目前是文档本身)中打印警告。该命令将输出数组,采用以下默认但可更改的设置:[3,2]\AB\dataA\AB[3,2]\AB[6,5]\AB\typesetarray\AB\AB

\def\arrayplnsep{\\---\\}
\def\arrayrowsep{\\}
\def\arraycolsep{,}
\def\arrayset#1{#1}

这些设置说明在平面、行、列之间排版的内容以及如何排版单元格本身。例如,更改\arraycolsep&将使排版适合环境。如果您希望直接排版,则将允许为每个单元格的排版分配固定空间。tabular\def\arrayset#1{\makebox[5ex][r]{#1}}

\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

1. 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} 

2. 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]

3. 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}

4. 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]

5. 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}

6. Error checking when existing array is reinitialized\hrulefill

\initarray\Q[2,2]
\Q[0,2,2] \Q[1,2,2] \QPLANES
\end{document}

此代码在日志文件中产生以下警告

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.

和这个输出

在此处输入图片描述

相关内容