如何在 foreach 循环中使用 \@namedef 全局定义颜色列表

如何在 foreach 循环中使用 \@namedef 全局定义颜色列表

动机

如标题所述,我试图定义一个命令,能够从颜色列表作为输入,创建一个颜色编号的列表。这是手动完成的 TikZ 中的箭头坐标

前期工作

我尝试在网站上搜索与该问题相关的问题,例如如何在 foreach 循环中定义宏并在迭代之间和循环后产生效果而不使用全局?如何在 foreach 循环中定义宏并在迭代之间和循环后产生效果而不使用全局?(尤其是 Martin 评论中显示的解决方案)。但是当定义基于\@namedef

最小非工作示例

这是我尝试过的:

\documentclass[11pt,a4paper]{article}
\usepackage{tikz}

\makeatletter

\newcommand{\setcolorlist}[1]{
        \foreach \listitem [count=\i] in {#1}{
            \global\let\@tempa\@namedef{color@\i}{\listitem}
        }
        \@tempa
}

% Command in which colors are necessary
\newcommand{\drawcoloredarrows}[1]{
    \foreach \i  in {#1}{
        \edef\mycolor{\@nameuse{color@\i}}
        \draw[\mycolor,-stealth] (0,-\i)--(2,-\i); 
    }
}

\makeatother

\begin{document}
\setcolorlist{red,cyan,blue,green}

\begin{tikzpicture}
    \drawcoloredarrows{1,...,4}
\end{tikzpicture}
\end{document}

得到:

在此处输入图片描述

如何运作

它的工作方式如下:

\documentclass[11pt,a4paper]{article}
\usepackage{tikz}

\makeatletter
\@namedef{color@1}{red}
\@namedef{color@2}{cyan}   
\@namedef{color@3}{blue} 
\@namedef{color@4}{green}  

\newcommand{\setcolorlist}[1]{
        \foreach \listitem [count=\i] in {#1}{
            \global\let\@tempa\@namedef{color@\i}{\listitem}
        }
        \@tempa
}

% Command in which colors are necessary
\newcommand{\drawcoloredarrows}[1]{
    \foreach \i  in {#1}{
        \edef\mycolor{\@nameuse{color@\i}}
        \draw[\mycolor,-stealth] (0,-\i)--(2,-\i); 
    }
}

\makeatother

\begin{document}
%\setcolorlist{red,cyan,blue,green}

\begin{tikzpicture}
    \drawcoloredarrows{1,...,4}
\end{tikzpicture}
\end{document}

得到:

在此处输入图片描述

答案1

用这个宏

\newcommand{\setcolorlist}[1]{
        \foreach \listitem [count=\i] in {#1}{
            \global\let\@tempa\@namedef{color@\i}{\listitem}
        }
        \@tempa
}

你基本上是在做

\global\let\@tempa\@namedef

确实打印出了“color@1red”等。然后\@tempa(现在是\@namedef)必须执行,但可能无法执行。

\setcolorlist{red,green,blue}你想做的

\@namedef{color@1}{red}
\@namedef{color@2}{green}
\@namedef{color@3}{blue}

所以你想说

\@namedef{color@\i}{<expansion of \listitem>}

但在全球范围内。由于\@namedef{x}扩展到

\expandafter\def\csname x\endcsname

并且您需要访问的扩展\listitem,以下就可以了

\newcommand{\setcolorlist}[1]{%
  \foreach \listitem [count=\i] in {#1}{%
     \global\@namedef{color@\i\expandafter}\expandafter{\listitem}
  }%
}

或者,既然你知道这一点,\listitem\i扩展为一个字符串,

\newcommand{\setcolorlist}[1]{%
  \foreach \listitem [count=\i] in {#1}{%
     \begingroup\edef\x{\endgroup
       \global\noexpand\@namedef{color@\i}{\listitem}}\x
  }%
}

请注意,Ahmed 方法也有效,因为在每个后续步骤中\listitem都定义为扩展为当前颜色名称。但是,如果您需要执行比简单的宏等效更复杂的事情,则该方法将失败。


强制expl3解决方案

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\setcolorlist}{ m }
 {
  \claudio_setcolorlist:n { #1 }
 }
\int_new:N \l_claudio_cycle_int
\cs_new_protected:Npn \claudio_setcolorlist:n #1
 {
  \int_zero:N \l_claudio_cycle_int
  \clist_map_inline:nn { #1 }
   {
    \int_incr:N \l_claudio_cycle_int
    \cs_set:cpn { color@ \int_to_arabic:n { \l_claudio_cycle_int } } { ##1 }
   }
 }
\ExplSyntaxOff

你可以选择全局或局部赋值(\cs_gset:cpn前者),但这不是必须的。所以这种方法优于后者\foreach,因为除非你需要,否则它不会强迫你进行全局定义。

答案2

尝试

\documentclass[11pt,a4paper]{article}
\usepackage{tikz}

\makeatletter
\newcommand{\setcolorlist}[1]{%
   \foreach \listitem [count=\i] in {#1}{
      \global\expandafter\let\csname color@\i\endcsname\listitem
   }
}

% Command in which colors are necessary
\newcommand{\drawcoloredarrows}[1]{
    \foreach \i  in {#1}{
        \draw[\@nameuse{color@\i},-stealth] (0,-\i)--(2,-\i); 
    }
}

\makeatother

\begin{document}
\setcolorlist{red,cyan,blue,green}
\begin{tikzpicture}
\drawcoloredarrows{1,...,4}
\end{tikzpicture}
\end{document}

以下是我推荐的方法:

\documentclass{article}
\usepackage{tikz}
\usepackage{keyreader}
\makeatletter
\krddefinekeys{claudiocolor}[claudio@col@]{%
  cmd/1/black;cmd/2/black;cmd/3/black;cmd/4/black;cmd/5/black;cmd/6/black;
}
\newcommand*\setcolorlist[1]{\krdsetkeys{claudiocolor}{#1}}
\newcommand*\usecolor[1]{\@nameuse{claudio@col@#1}}
% Command in which colors are necessary:
\newcommand*\drawcoloredarrows[1]{%
  \foreach \x in {#1}{%
    \draw[\usecolor\x,-stealth] (0,-\x)--(2,-\x);
  }%
}
\makeatother

\begin{document}
\setcolorlist{1=red,2=blue,3=cyan,4=green,5=magenta,6=purple}
\begin{tikzpicture}
\drawcoloredarrows{1,...,4}
\end{tikzpicture}
\end{document}

相关内容