¿Cómo definir macros en un bucle foreach con efectos entre iteraciones y después del bucle sin usar global?

¿Cómo definir macros en un bucle foreach con efectos entre iteraciones y después del bucle sin usar global?

Sin usar \global, el siguiente código:

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

produce un documento que contiene:

    para cada 1
\myarray: macro:->inicio
\valmax: macro:->0
    para cada 8
\myarray: macro:->inicio
\valmax: macro:->1.0
    para cada -3
\myarray: macro:->inicio
\valmax: macro:->8.0
    adentro
\myarray: macro:->inicio,1,8,-3
\valmax: macro:->8.0
    afuera
\myarray: \relajarse
\valmax: \relajarse

¡Este resultado me sienta bien!

Pero, ¿existe una mejor manera de definir macros \appendbyforeachy \defincbyforeachal mismo tiempo lograr los mismos efectos?

¿ etextoolsEl paquete es realmente práctico aquí?

Respuesta1

Nota:Este código siempre usa etextools. Antes de aceptar mi respuesta a mi propia pregunta, espero que otros me ofrezcan soluciones más interesantes (sin etextools, más efectivas, más rápidas, más simples...). ¡Pero siempre sin usar \global!

Editar:Aquí una nueva versión sin valores ampliados y con sólo dos macros.

  1. \afteriterationdefpara (re)definir una macro después de la iteración actual.

  2. \afterforeachdefpara (re)definir una macro después de foreach (y después de la iteración).

Aquí está el código de estas dos macros:

\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

Y un ejemplo:

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

Este ejemplo produce este texto:

foreach 1: \myarray: macro:->init,1, \myvalue: macro:->1.0
foreach 8: \myarray: macro:->init,1,8, \myvalue: macro:->8.0
foreach -3: \myarray: macro:->init,1,8,-3, \myvalue: macro:->-24.0
foreach -1: \myarray: macro:->init,1,8,-3,-1, \myvalue: macro:->24.0
dentro del grupo: \myarray: macro:->init,1,8,-3,-1, \myvalue: macro:->24.0
grupo externo: \myarray: \relax, \myvalue: \relax

Edición 2:Otro ejemplo con dos anidados \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}

Este ejemplo produce este texto:

int foreach 1: \myarray: macro:->init,(1,1), \myvalue: macro:->2.0
int foreach 1: \myarray: macro:->init,(1,1),(1,2), \myvalue: macro:->4.0
int foreach 1: \myarray: macro:->init,(1,1),(1,2),(1,3), \myvalue: macro:->7.0
text foreach 1: \myarray: macro:->init,(1,1),(1,2),(1,3), \myvalue: macro:->7.0
int foreach 2: \myarray: macro:->init,(1,1),(1,2),(1,3),(2,1), \myvalue: macro:->9.0
int foreach 2: \myarray: macro:->init,(1,1),(1,2),(1,3),(2,1),(2,2), \myvalue: macro:-> 13.0
int foreach 2: \myarray: macro:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3), \ mivalor: macro:->19.0
text foreach 2: \myarray: macro:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3), \ mivalor: macro:->19.0
int foreach 3: \myarray: macro:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),( 3,1), \mivalor: macro:->22.0
int foreach 3: \myarray: macro:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),( 3,1),(3,2), \mivalor: macro:->28.0
int foreach 3: \myarray: macro:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),( 3,1),(3,2),(3,3), \mivalor: macro:->37.0
text foreach 3: \myarray: macro:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),( 3,1),(3,2),(3,3), \mivalor: macro:->37.0
dentro del grupo: \myarray: macro:->init,(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3 ,1),(3,2),(3,3), \mivalor: macro:->37.0
grupo externo: \myarray: \relax, \myvalue: \relax

información relacionada