6

I've looked around and can't seem to find anywhere, but I was wondering if there is somewhere you can do something like the following:

\newcommand{\loopy}[1]{
    \begin{tikzpicture}
        \foreach \x in #1 {
            \foreach \y in \x {
                \node at (\y_1,\y_2);
            }
        }
    \end{tikzpicture}
}

\loopy{{{1,2},{2,3}}}

Then the 'loopy' command would go through and plot nodes at (1,2) and (2,3). I'm not sure this is even possible or how you would go about doing it?

Additionally, would there be a way to see the number of elements within a number? So say I pass in

\loopy{{{1,2,3},{2,3}}}

Is there a way to know that the first set has 3 elements and the second set has 2?

Edit (Adding more description)

The above example was to simplistic, so I'll make a more 'complex' example to show kinda what I'm trying to do:

\newcommand{\loopy}[1]{
    \begin{tikzpicture}
        \foreach \x in #1 {
            \if \x has 2 elements {
                \foreach \y in \x {
                    \node at (\y_1,\y_2);
                }
            }
            \else if \x has 3 elements {
                \foreach \y in \x {
                    \node at (\y_1,\y_2) {\y_3};
                }
            }
            \else if \x has 4 elements {
                \foreach \y in \x {
                    \node at (\y_1,\y_2);
                    \node at (\y_3,\y_4);
                }
            }
        }
    \end{tikzpicture}
}

\loopy{{{1,2},{1,2,3},{2,3,4,5}}}
8
  • 1
    \newcommand{\loopy}[1]{\tikz{\foreach \x in #1 {\node[draw] at (\x){};}}} is sufficient. For the counting, as far as I know, no. You have to touch all elements to count the elements.
    – percusse
    Jun 2, 2014 at 11:09
  • What do you mean by touch? Also, I wanted to access each element individually. The example above was just a torn down version hence why I asked the supplementary question. I'll likely be passing 3-4 element sets and would need to know each item within each set individually. (I'll update the question to better explain the question) Jun 2, 2014 at 11:23
  • I mean there is no inherent attribute of the array that holds the element number. You need to explicitly go through the elements(count) to get the number of elements. That means you have to "touch" every element at least once to count and possibly more if you want to switch based on the no of elements. It's not difficult but just extra programming steps.\
    – percusse
    Jun 2, 2014 at 13:37
  • And that's the part I don't understand. How do you explicitly go through each element? Do I just keep making nested foreach loops then? Jun 2, 2014 at 14:27
  • 1
    @AramPapazian if this is solved, would you like to write a self-answer so it can be useful to future visitors? Jan 11, 2015 at 2:23

3 Answers 3

2

The question seems a bit ill-defined, but one can indeed parse a general list in a nested way, and do different things based on the list length of each successive rank-1 list. Here

\loopy{1,2: 2,3,7: 2,4,4,5}

will place a 2 at location (1,2), since it was a 2-element list. It will place a 3_7 at location (2,3), since 7 was the third element of the list starting with the coordinates (2,3). Finally, it will place a 4_1 and 4_2 at (2,4) and (4,5) since the 4 element list began with 2,4 and concluded with 4,5.

\documentclass{article}
\usepackage{listofitems,tikz}
\newcommand{\loopy}[1]{%
  \setsepchar{:/,}%
  \readlist\mylist{#1}%
    \begin{tikzpicture}
        \foreachitem\x\in\mylist[]{%
          \ifnum\listlen\mylist[\xcnt]=2\relax
            \node at (\mylist[\xcnt,1],\mylist[\xcnt,2]){$2$};
          \else
            \ifnum\listlen\mylist[\xcnt]=3\relax
              \node at (\mylist[\xcnt,1],\mylist[\xcnt,2]){$3_{\mylist[\xcnt,3]}$};
            \else
              \ifnum\listlen\mylist[\xcnt]=4\relax
                \node at (\mylist[\xcnt,1],\mylist[\xcnt,2]){$4_1$};
                \node at (\mylist[\xcnt,3],\mylist[\xcnt,2]){$4_2$};
              \fi
            \fi
          \fi
        }
   \end{tikzpicture}
}
\begin{document}
\loopy{1,2: 2,3,7: 2,4,4,5}
\end{document}

enter image description here

1

Here is one "low level" solution.

I define \def\switch#1,#2,#3,#4,#5;{...} which is called with something like \switch1,2,3,,,,;, which set the parameter #4 to be empty (and #5 is ,,). So we can check that there are only 3 parameters by \ifx,#4,<executed when #4 is empty>\else...\fi.

Here is the complete code:

\documentclass[tikz,border=7pt]{standalone}
\def\switch#1,#2,#3,#4,#5;{
  \ifx,#2,\node[green] at (#1,1) {one variable : #1};\else
  \ifx,#3,\node[red] at (#1,#2) {two variables: #1,#2};\else
  \ifx,#4,\node[blue] at (#2,#3) {three variables: #1,#2,#3};\else
          \draw[orange] (#1,#2) -- node[sloped, above]{four variables:#1,#2,#3,#4} (#3,#4);
  \fi\fi\fi
}
\newcommand*{\loopy}[1]{
  \begin{tikzpicture}
    \foreach \x in {#1} {
      \expandafter\switch\x,,,,;
    }
  \end{tikzpicture}
}

\begin{document}
    \loopy{{1},{1,2},{1,2,3},{-1,3,4,5}}
\end{document}

enter image description here

3
  • you can use \ifcase
    – percusse
    Apr 2, 2018 at 20:41
  • @percusse how can I use \ifcase to detect the first empty argument ?
    – Kpym
    Apr 2, 2018 at 20:56
  • Oh yes you are doing the reverse indeed then nevermind.
    – percusse
    Apr 2, 2018 at 21:02
1

I don't know if it is still undocumented but there is a math function dim for counting stuff inside a comma separated array. So you can use that to branch of via \ifnum.

\documentclass{article}
\usepackage{pgfmath,pgffor}
\def\loopy#1{%
  \foreach\x in#1{%
    \pgfmathdim{\x}\edef\tmp{\noindent There are \pgfmathresult{} elements.\par}\tmp%
  }
}
\begin{document}
\loopy{{{1,2},{1,2,3},{2,3,4,5}}}
\end{document}

enter image description here

1
  • Still not in the documentation, I think, but it is documented on TeX.SX ;)
    – Kpym
    Apr 3, 2018 at 9:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .