关于使用 foreach 语法绘制一些 node 的问题

发布于 2022-08-02 17:42:55

实际上是我之前提出的一个问题,我有了一些新的想法,但还是不能解决。
首先我的目的是输出以下这样分布的 node:5874c2bd61dac4437931745cb0d42366.png

我的代码是

\begin{tikzpicture}
 \foreach \x/\y/\z in{
  0/0/A,
  2/0/B,
  0/-1/C,
  2/-1/D
 }
 {\node at(\x,\y){\z};}
\end{tikzpicture}

这样是可以实现的,但我想简化输入,于是想这样操作:

\begin{tikzpicture}
 \foreach \x in{0,2}
 \foreach \y in{0,-1}
 \foreach \z in{A,B,C,D}
 \foreach \m/\n/\l in{\x/\y/\z}
 {\node[draw] at(\m,\n){\l};}
\end{tikzpicture}

但结果是这样8b245cbd209ffe14709d8a583bf959ac.png
可以看到,每个 node 上并不是只有一个字母,而应该是16个,也就是说最后的标签变量把所有的循环都走了一遍,但现在我只想输出一个字母,也就是让\foreach \m/\n/\l in{\x/\y/\z}中的\x/\y/\z展开,请问有什么方法可以实现这样的效果?谢谢。

查看更多

关注者
0
被浏览
1.2k
鱼香肉丝没有鱼先生
鱼香肉丝没有鱼先生.

仔细整理一下你的代码,其实你在嵌套循环

\begin{tikzpicture}
 \foreach \x in{0,2} %2
 {
   \foreach \y in{0,-1} %2
   {
     \foreach \z in{A,B,C,D} %4
     {
      \foreach \m/\n/\l in{\x/\y/\z}
      {
        \node[draw] at(\m,\n){\l}; % 2 x 2 x 4 = 16
      }
     }
   }
 }
\end{tikzpicture}

循环次数分别是 2,2,4,1. 所以一共是 2x2x4x1=16 次,你的这种想法我大概明白了,但是目前我并没有好的办法.
或许可以使用计数器来代替第三层循环,如下

\begin{tikzpicture}
\newcounter{node}
\setcounter{node}{1}  
 \foreach \x in{0,2} %2
 {
   \foreach \y in{0,-1} %2
   {
      \node[draw] at (\x,\y){\Alph{node}\stepcounter{node}};
   }
 }
\end{tikzpicture}

给另外一个例子,或许可以给你提供一点思路,如下:
我想构造两个循环,但是他们不嵌套,而是一一对应,第一层为
1,2,3,4,...,10, 第二层为2,4,6,8,...,20,当然你可以使用:

\foreach \x/\y in {1/2,2/4,3/6,4/8,5/10,6/12,7/14,8/16,9/18,10/20}
{
  ...
}

这样固然是可行的, 但是难免有些繁琐, 毕竟两个循环的值是有函数关系的,那么可以:
方法一

\foreach \x in {1,2,...,10}
{
  \pgfmathsetmacro{\y}{2*\x} % \y = 2*\x 
  \node[] at (\x,0) {\y};
}

方法二

\foreach \x [count=\xc] in {1,2,...,10}
{
  \foreach \y [count=\yc] in {2,4,...,20}
  {
    \ifnum\xc=\yc
    \node[] at (\x,0) {\y};
    \fi 
  }
}

希望能够帮助到你!


关于二维数组,可以使用 LaTeX3 实现一个阉割版的 二维数组

\documentclass{article}
\usepackage{tikz}

\begin{document}
\ExplSyntaxOn
\seq_new:N \l_node_row_seq  
\seq_new:N \l_node_tmp_seq 
\cs_set:Npn \GetArray #1 {
  \seq_set_split:Nnn \l_node_row_seq {;} {#1}
  \int_step_inline:nn{\seq_count:N \l_node_row_seq}
  {
    \seq_if_exist:cF {l_node_row_##1_seq}
    {
      \seq_new:c {l_node_row_##1_seq}
    }
    \exp_args:Ncx\seq_set_from_clist:Nn {l_node_row_##1_seq} {\seq_item:Nn \l_node_row_seq{##1}}
  }
}

\cs_set:Npn \PrintArray [#1][#2] {
  \tl_if_empty:nTF { #1 }
  {
    \tl_if_empty:nTF { #2 }
    {
      \seq_use:Nn \l_node_row_seq {,}
    }
    {
      \int_step_inline:nn{\seq_count:N \l_node_row_seq}
      {
        \seq_put_right:Nn \l_node_tmp_seq {\seq_item:cn {l_node_row_##1_seq}{#2}}
      }
      \seq_use:Nn \l_node_tmp_seq {,}
    }
  }
  {
    \tl_if_empty:nTF {#2}
    {
      \seq_use:cn {l_node_row_#1_seq}{,}
    }
    {
      \seq_item:cn {l_node_row_#1_seq}{#2}
    }
  }
}
\ExplSyntaxOff


\GetArray
{
  A,B,C;
  D,E,F;
  G,H,I
}
\PrintArray[][]\par 
\PrintArray[1][]\par 
\PrintArray[][2]\par 
\PrintArray[1][2]

\vspace*{1cm}

\begin{tikzpicture}
\GetArray
{
  A,B,C;
  D,E,F;
  G,H,I
}
\foreach \x in {1,2,3}
{
  \foreach \y in {1,2,3}
  {
    \node[draw] at (\x,\y) {\PrintArray[\x][\y]};
  }
}
\end{tikzpicture}

\end{document}

QQ截图20220802234351.png

3 个回答
雾月
雾月 2022-08-02
这家伙很懒,什么也没写!

其实需要的就是一个多维数组而已。简单描述一下就是:

a[M][N] = {...} % 以 1 起始
for (i=1; i<=M; i++)
    for (j=1; j<=N; i++)
        node(a[i][j]);

只是在 LaTeX 中(包括 LaTeX3)并没有这样的数据结构。LuaTeX 倒是可以用 table 实现。

要使用宏来实现,简单的就是使用多个 seq 或 clist 或 prop。这样实现的话效率很低。

或者也可以直接用宏保存:

% \@namedef := \expandafter \def \csname #1\endcsname
\@namedef{data@1@1}{A}
\@namedef{data@1@2}{B}
\@namedef{data@2@1}{C}
\@namedef{data@2@2}{D}

然后直接用

% \UseName := \csname #1\endcsname
\foreach \i .....
   \foreach \j .....
     {\node {\UseName{data@\i @\j}};}
shadow
shadow 2022-08-02
这家伙很懒,什么也没写!

各位大佬,我发现我的问题就可以用 matrix 库解决,我之前只关注了 matrix 模块而没有关注 matrix 库,现在才了解到。也许是我太过于愚蠢。不管怎样都感谢大家提供的思路和方法,也让我学到一些新的东西。

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览