Без использования \global
следующий код:
\documentclass{minimal}
\usepackage[T1]{fontenc}
\usepackage{tikz}
\usepackage{etextools}
\newcommand\appendbyforeach[2]{%
\AfterGroup*{\noexpand\AfterGroup{\noexpand\edef\noexpand#1{\noexpand#1#2}}}
}
\newcommand\defincbyforeach[2]{%
\AfterGroup*{\noexpand\def\noexpand#1{#2}}
\AfterGroup*{\noexpand\AfterGroup{\noexpand\def\noexpand#1{#2}}}
}
\newcommand\meaningwithname[1]{\textbackslash#1: \expandafter\meaning\csname #1\endcsname}
\newcommand\mymacro{
\begingroup
\def\myarray{init}
\def\valmax{0}
\foreach \i in {1,8,-3}{
\appendbyforeach{\myarray}{,\i}
\pgfmathsetmacro{\max}{\valmax < \i ? \i : \valmax}
\defincbyforeach\valmax{\max}
%%% print state of \myarray and \valmax
foreach \i\\\meaningwithname{myarray}\\\meaningwithname{valmax}\par
}
inside\\\meaningwithname{myarray}\\\meaningwithname{valmax}\par
\endgroup
outside\\\meaningwithname{myarray}\\\meaningwithname{valmax}\par
}
\begin{document}\mymacro\end{document}
создает документ, содержащий:
для каждого 1 \myarray: макрос:->init \valmax: макрос:->0 для каждого 8 \myarray: макрос:->init \valmax: макрос:->1.0 foreach -3 \myarray: макрос:->init \valmax: макрос:->8.0 внутри \myarray: макрос:->init,1,8,-3 \valmax: макрос:->8.0 снаружи \myarray: \relax \valmax: \relax
Этот результат меня вполне устраивает!
Но есть ли лучший способ определения макросов \appendbyforeach
, \defincbyforeach
позволяющий достичь тех же эффектов?
Действительно ли etextools
упаковка здесь практична?
решение1
Примечание:Этот код всегда использует etextools
. Прежде чем принять мой ответ на мой собственный вопрос, я надеюсь, что другие предложат мне более интересные решения (без etextools
, более эффективные, быстрые, простые...). Но всегда без использования \global
!
Редактировать:Вот новая версия без расширенных значений и всего с двумя макросами.
\afteriterationdef
для (пере)определения макроса после текущей итерации.\afterforeachdef
для (пере)определения макроса после foreach (и после итерации).
Вот код этих двух макросов:
\documentclass{minimal}
\usepackage[T1]{fontenc}
\usepackage{tikz}
\usepackage{etextools}
\makeatletter
% define a macro after current iteration
\newcommand\afteriterationdef[1]{\aftergroup@def#1}
% define a macro after foreach (and after iteration)
\newcommand\afterforeachdef[1]{\afteriterationdef{#1}\AfterGroup{\aftergroup@def#1}}
\makeatother
И пример:
\newcommand\meaningwithname[1]{%
\textbackslash#1: \expandafter\meaning\csname #1\endcsname}
\newcommand\mymacro{
{
\def\myarray{init}
\def\myvalue{1}
\foreach \i in {1,8,-3,-1}{
% append some value to \myarray
\edef\myarray{\myarray,\i}
\afterforeachdef\myarray
% incremental definition of \mtvalue
\pgfmathsetmacro{\myvalue}{\myvalue*\i}
\afterforeachdef\myvalue
%%% print meaning of \myarray and \myvalue at each iteration
foreach \i: \meaningwithname{myarray}, \meaningwithname{myvalue}\par
}
%%% print meaning of \myarray and \myvalue after \foreach
inside group: \meaningwithname{myarray}, \meaningwithname{myvalue}\par
}
%%% print meaning of \myarray and \myvalue outside
outside group: \meaningwithname{myarray}, \meaningwithname{myvalue}\par
}
\begin{document}\mymacro\end{document}
В этом примере получается следующий текст:
foreach 1: \myarray: макрос:->init,1, \myvalue: макрос:->1.0 foreach 8: \myarray: макрос:->init,1,8, \myvalue: макрос:->8.0 foreach -3: \myarray: макрос:->init,1,8,-3, \myvalue: макрос:->-24.0 foreach -1: \myarray: макрос:->init,1,8,-3,-1, \myvalue: макрос:->24.0 внутри группы: \myarray: макрос:->init,1,8,-3,-1, \myvalue: макрос:->24.0 внешняя группа: \myarray: \relax, \myvalue: \relax
Редактировать 2:Еще один пример с двумя вложенными \foreach
:
\newcommand\mymacrowithnestedforeach{
{
\def\myarray{init}
\def\myvalue{1}
\foreach \i in {1,...,3}{
\foreach \j in {1,...,3}{
% append some value to \myarray
\edef\myarray{\myarray,(\i,\j)}
\afterforeachdef\myarray
% incremental definition of \myvalue
\pgfmathsetmacro{\myvalue}{\myvalue+\j*\i}
\afterforeachdef\myvalue
%%% print meaning of \myarray and \myvalue at each iteration
int foreach \i: \meaningwithname{myarray}, \meaningwithname{myvalue}\par
}
%
\afterforeachdef\myarray
\afterforeachdef\myvalue
%%% print meaning of \myarray and \myvalue at each iteration
ext foreach \i: \meaningwithname{myarray}, \meaningwithname{myvalue}\par
}
%%% print meaning of \myarray and \myvalue after \foreach
inside group: \meaningwithname{myarray}, \meaningwithname{myvalue}\par
}
%%% print meaning of \myarray and \myvalue outside
outside group: \meaningwithname{myarray}, \meaningwithname{myvalue}\par
}
\begin{document}\mymacrowithnestedforeach\end{document}
В этом примере получается следующий текст:
int foreach 1: \myarray: макрос:->init,(1,1), \myvalue: макрос:->2.0 int foreach 1: \myarray: макрос:->init,(1,1),(1,2), \myvalue: макрос:->4.0 int foreach 1: \myarray: макрос:->init,(1,1),(1,2),(1,3), \myvalue: макрос:->7.0 ext foreach 1: \myarray: макрос:->init,(1,1),(1,2),(1,3), \myvalue: макрос:->7.0 int foreach 2: \myarray: макрос:->init,(1,1),(1,2),(1,3),(2,1), \myvalue: макрос:->9.0 int foreach 2: \myarray: макрос:->init,(1,1),(1,2),(1,3),(2,1),(2,2), \myvalue: макрос:->13.0 int foreach 2: \myarray: макрос:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3), \myvalue: макрос:->19.0 ext foreach 2: \myarray: макрос:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3), \myvalue: макрос:->19.0 int foreach 3: \myarray: макрос:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1), \myvalue: макрос:->22.0 int foreach 3: \myarray: макрос:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2), \myvalue: макрос:->28.0 int foreach 3: \myarray: макрос:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3), \myvalue: макрос:->37.0 ext foreach 3: \myarray: макрос:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3), \myvalue: макрос:->37.0 внутри группы: \myarray: макрос:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3), \myvalue: макрос:->37.0 внешняя группа: \myarray: \relax, \myvalue: \relax