20

A few of my macros currently require the user to pass the length of an array along with the array itself. It would be nice if the length could be calculated for them, as the user in question (myself) seems incapable of consistently counting beyond 3.

I've checked the pgfmanual's chapters 56 (for loops, where most of this is getting used) and 63 (mathematical functions where arrays are defined). In some sense, this is just counting commas (which I don't know how to do), but PGF has a few exceptions in arrays with () and {} allowing entries to have commas within them.

Can someone write a reasonable pgf math function that takes an array as its only argument and returns the length of that array as its result?

Jack Schmidt
  • 1,137

3 Answers3

20

In the cvs version of pgf/tikz or in the version available for texlive at tlcontrib there is an experimental undocumented dim function in pgfmath defined as

\makeatletter
% dim function: return dimension of an array
% dim({1,2,3}) return 3
% dim({{1,2,3},{4,5,6}}) return 2
\pgfmathdeclarefunction{dim}{1}{%
  \begingroup
    \pgfmath@count=0\relax
    \expandafter\pgfmath@dim@i\pgfutil@firstofone#1\pgfmath@token@stop
    \edef\pgfmathresult{\the\pgfmath@count}%
    \pgfmath@smuggleone\pgfmathresult%
  \endgroup}

\def\pgfmath@dim@i#1{%
    \ifx\pgfmath@token@stop#1%
    \else
      \advance\pgfmath@count by 1\relax
      \expandafter\pgfmath@dim@i
    \fi}

\makeatother

This can however be very slow for large arrays (any suggestions are welcome!).

You can use it this way

\documentclass{standalone}
\usepackage{pgfmath}
\begin{document}
  The dimension of $\{1,2,3\}$ is
  \pgfmathparse{dim({1,2,3})}\pgfmathresult.

  The dimension of $\{1,2,\{3,4\},5\}$ is
  \pgfmathparse{dim({1,2,{3,4},5})}\pgfmathresult. 
\end{document}

dim of an array

cjorssen
  • 10,032
  • 4
  • 36
  • 126
  • Thanks. I had tried to write this myself and failed. I could never get the result to be returned. It would be nice for the manual to have more examples of functions, since returning the number was very difficult. – Jack Schmidt Nov 28 '11 at 21:15
  • 1
    There is a hidden danger in this solution. If there is only 1 element in the array, for example number 10 used as in the provided examples. It will not return 1 as an answer, but it will count the elements of that number and return 2 as an answer. Some examples: The dimension of {10} is 2., The dimension of {"10"} is 2. and The dimension of {{10}} is 1. – karu Aug 01 '14 at 15:21
  • @karu You're right. Thanks for spotting this. It may be something to fix in the pgfmath parser itself. The internal form of the array {1,2,3} is {{1}{2}{3}} while for the array {1} it is {1} (and IMHO should be {{1}}). But I need some time to dig into it. – cjorssen Aug 02 '14 at 14:19
18

It is also relatively easy to solve using just TikZ:

\documentclass{article}
\usepackage{tikz}
\newcounter{arraycard}
\def\arrayLength#1{%
  \setcounter{arraycard}{0}%
  \foreach \x in #1{%
    \stepcounter{arraycard}%
  }%
  \the\value{arraycard}%
}  
\begin{document}
  \noindent
  The length of $\{1,2,3\}$ is \arrayLength{{1,2,3}}.\\
  And the length of $\{1,2,\{3,4\},5\}$ \arrayLength{{1,2,{3,4},5}}.
\end{document}

This just uses foreach to iterate over the list and increases a count on every element seen.

Moriambar
  • 11,466
Roelof Spijker
  • 17,663
  • 5
  • 55
  • 63
12

Here is a (community wiki) answer written with great assistance from Bruno Le Floch, Joseph Wright, egreg, and probably a few others on the texsx chat.

\usepackage{expl3} 
\ExplSyntaxOn 
\cs_new:Npn \Counter #1 \Stopper { \tl_length:n {#1} } 
\ExplSyntaxOff
\pgfmathdeclarefunction{countarray}{1}{\edef\pgfmathresult{\Counter#1\Stopper}}

It can be used as in:

\pgfmathtruncatemacro{\Length}{countarray({1,2,3,4})}

Which sets \Length to 4.

Jack Schmidt
  • 1,137