# How to make macro with string variable and returning array?

I want to make a macro "\mymacro" which has two string variables and returns array.

The two variables are arbitrary string characters and has the same length. The length of the strings are also arbitrary. "\mymacro" returns an array whose rows are the string variables. For example,

\mymacro{abc}{def}


should return

\begin{array}{ccc}
a&b&c\\\hline
d&e&f
\end{array}


Can I make such macro? Thank you for your cooperation.

## 4 Answers

You can iterate over the list the tricky bit is to avoid adding a &at the end here I do add it but use \omit to avoid generating a visible empty column (with an over-long \hline)

\documentclass{article}

\usepackage{amsmath}

\newcommand\mymacro[2]{\begin{matrix}\zz#1\zzz\\\hline\zz#2\zzz\end{matrix}}

\def\zz#1{#1&\zz}
\def\zzz#1#2{\omit}

\begin{document}

$\mymacro{abc}{def}$

$\mymacro{123456}{aaabbb}$

\end{document}

• As always, a masterful answer! Jan 19 at 16:12
• Thank you for your quick and very simple answer! Jan 19 at 17:39
\documentclass{article}
\newcommand\mymacro[2]{%
\process{\tmpA}{#1}%
\process{\tmpB}{#2}%
\begin{array}{\arwd}
\tmpA\\\hline\tmpB
\end{array}
}
\newcommand\process[2]{\def\arwd{}\def#1{}\processA#1#2\relax}
\makeatletter
\def\processA#1#2#3\relax{%
\if\relax#1\relax\else\g@addto@macro#1{&}\fi
\g@addto@macro#1{#2}%
\g@addto@macro\arwd{c}%
\ifx\relax#3\relax\else\processA#1#3\relax\fi
}
\makeatother
\begin{document}
$\mymacro{abc}{def}$

$\mymacro{12345}{67890}$
\end{document}


• Thank you for your answering question. I am not familiar with tex programming, so your answers are very educative for me. Jan 19 at 18:17

You can do several lines without the need to count how long is any item.

\documentclass{article}
\usepackage{booktabs} % better rules

\ExplSyntaxOn

\NewDocumentCommand{\mymacro}{O{\\}m}
{% #1 = separator, #2 = data
\fukai_mymacro:nn { #1 } { #2 }
}

\int_new:N \l__fukai_mymacro_length_int
\seq_new:N \l__fukai_mymacro_body_seq
\seq_new:N \l__fukai_mymacro_row_seq

\cs_new_protected:Nn \fukai_mymacro:nn
{
\seq_set_split:Nnn \l__fukai_mymacro_body_seq { #1 } { #2 }
\int_zero:N \l__fukai_mymacro_length_int
\seq_map_inline:Nn \l__fukai_mymacro_body_seq
{
\int_compare:nT { \l__fukai_mymacro_length_int < \tl_count:n { ##1 } }
{
\int_set:Nn \l__fukai_mymacro_length_int { \tl_count:n { ##1 } }
}
}
\begin{array}{ * { \l__fukai_mymacro_length_int } { c } }
\seq_map_indexed_function:NN \l__fukai_mymacro_body_seq \__fukai_mymacro_row:nn
\end{array}
}

\cs_new_protected:Nn \__fukai_mymacro_row:nn
{% #1 is the index, #2 is the item
\int_compare:nF { #1 = 1 } { \\ \midrule }
\seq_set_split:Nnn \l__fukai_mymacro_row_seq { } { #2 }
\seq_use:Nn \l__fukai_mymacro_row_seq { & }
}

\ExplSyntaxOff

\begin{document}

$\mymacro{abc \\ def }$

$\mymacro{abcde \\ fg \\ uvw}$

$\mymacro[,]{ab,def}$

\end{document}


The row separator is, by default \\, but it can be set differently with the optional argument.

The argument is split at the chosen separator; then each item's length is computed to determine the number of columns. Next each row is produced by splitting “at nothing”.

If all your tables have just two rows, you can do in a similar way.

\documentclass{article}
\usepackage{booktabs} % better rules

\ExplSyntaxOn

\NewDocumentCommand{\mymacro}{mm}
{
\fukai_mymacro:nn { #1 } { #2 }
}

\seq_new:N \l__fukai_mymacro_row_seq

\cs_new_protected:Nn \fukai_mymacro:nn
{
\begin{array}
{
* { \int_max:nn { \tl_count:n { #1 } } { \tl_count:n { #2 } } } { c }
}
\seq_set_split:Nnn \l__fukai_mymacro_row_seq { } { #1 }
\seq_use:Nn \l__fukai_mymacro_row_seq { & }
\\ \midrule
\seq_set_split:Nnn \l__fukai_mymacro_row_seq { } { #2 }
\seq_use:Nn \l__fukai_mymacro_row_seq { & }
\end{array}
}

\ExplSyntaxOff

\begin{document}

$\mymacro{abc}{def}$

$\mymacro{abcde}{uvw}$

$\mymacro{ab}{def}$

\end{document}


• Thank you for your answering question. It was very helpful to give more general answer. Jan 19 at 18:20

The following MWE forms a fully expandable macro mechanism where an outer loop iterates on a list of undelimited arguments forming the rows of the array and where with each "row" of the array an inner loop iterates on the list of column-entries, also a list of undelimited arguments.

\makeatletter
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\expandafter\UD@stopromannumeral\@secondoftwo}{%
\expandafter\UD@stopromannumeral\@firstoftwo}%
}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=\^^00}%
%%-----------------------------------------------------------------------------
\@ifdefinable\UD@loopovercolumentries{%
\long\def\UD@loopovercolumentries#1#2#3#4\bizarre#5#6#7#8{%
% #1 - if #2=\@firstoftwo, then
%       <needed amount of c detected with previous columns> minus <amount of column-entries processed in this loop so far>
%      if #2=\@secondoftwo, then
%      <amount of c> by which <amount of c needed by this row> so far exceeds <needed amount of c detected with previous columns>
% #2 - \firstoftwo/\secondoftwo - fork if c need to be removed/added from #1;
%      when the loop teminates: fork if this column required more c than
%      previous columns
% #3 - first column-entry not processed so far
% #4 - remaining column-entries not processed so far
% #5 - column-separator to prepend to row in this iteration
% #6 - stuff to append to column-separator in next iteration
% #7 - needed amount of c detected with previous columns
% #8 - rows and columns gathered so far
\UD@CheckWhetherNull{#4}{#2{\UD@loopoverrowentries{#7}}{\UD@loopoverrowentries{#7#1}}{#8}}{%
#2{\ifcat$#1$\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}%
{\@firstoftwo}%
{\UD@loopovercolumentries{#1c}{\@secondoftwo}}%
{\expandafter\UD@loopovercolumentries\expandafter{\@firstoftwo{}#1}{#2}}%
#4\bizarre{#5#6}{}{#7}{#8#5#3}%
}%
}%
}%
\@ifdefinable\UD@loopoverrowentries{%
\long\def\UD@loopoverrowentries#1#2#3#4\bizarre#5#6{%
% #1 - needed amount of c detected so far
% #2 - rows and columns gathered so far
% #3 - first row/first list of column-entries not processed so far
% #4 - remaining rows/remaining lists of column-entries not processed so far
% #5 - row-separator to prepend to row in this iteration
% #6 - stuff to append to row-separator in next iteration
\UD@CheckWhetherNull{#4}{%
\ifcat$#1$\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\UD@stopromannumeral}{\UD@stopromannumeral\begin{array}{#1}#2\end{array}}%
}{%
\UD@loopovercolumentries{#1}{\@firstoftwo}#3{{}{}}\bizarre{}{&}{#1}{#2#5}%
#4\bizarre{#5#6}{}%
}%
}%
}%
\newcommand\mymacro[1]{%
% \romannumeral-trickery, not to obtain roman numerals but to ensure
% that the result can be obtained by triggering exactly two
% expansion-steps:
\romannumeral
\expandafter\@firstoftwo\expandafter{\expandafter%
\UD@stopromannumeral
\romannumeral\UD@loopoverrowentries{}{}#1{{}{}}\bizarre{}{\\\hline}%
}{}%
}%
%%-----------------------------------------------------------------------------
\makeatother

\documentclass{article}

\begin{document}

$\mymacro{{abc}{defghij}{kl}{mno}{pqr}}$

$\mymacro{{ab}{cd}{ef}{gh}{ij}{kl}{mn}{op}{qr}}$

$\mymacro{{abcdef}{gh}{ijk}{lmn}{op}{qr}}$

$\mymacro{{{ab}{cd}{ef}}{gh}{ijk}{lmn}{op}{qr}}$

\end{document}
`