Interesting question, but is there a real gain?
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% user interface
\NewDocumentCommand{\mymacro}{mmm}
{% #1 = column headers, #2 = row headers, #3 = entries
\gabriel_mymacro:nnn { #1 } { #2 } { #3 }
}
% variables
\tl_new:N \l__gabriel_mymacro_body_tl
\tl_new:N \l__gabriel_mymacro_row_tl
\seq_new:N \l__gabriel_mymacro_entries_seq
% functions
\cs_new_protected:Nn \gabriel_mymacro:nnn
{
% clear the tl containing the body and collect the entries
\tl_clear:N \l__gabriel_mymacro_body_tl
\seq_set_split:Nnn \l__gabriel_mymacro_entries_seq { , } { #3 }
% make the first row
\tl_put_right:Nx \l__gabriel_mymacro_body_tl
{
\clist_item:nn { #2 } { 1 }
}
\clist_map_function:nN { #1 } \__gabriel_mymacro_add_entry:n
\tl_put_right:Nn \l__gabriel_mymacro_body_tl { \\ \hline }
% build the following rows
\int_step_inline:nn { \clist_count:n { #2 } - 1 }
{
\tl_put_right:Nx \l__gabriel_mymacro_body_tl
{
\clist_item:nn { #2 } { ##1 + 1 }
}
\seq_pop_left:NN \l__gabriel_mymacro_entries_seq \l__gabriel_mymacro_row_tl
\tl_map_function:NN \l__gabriel_mymacro_row_tl \__gabriel_mymacro_add_entry:n
\tl_put_right:Nn \l__gabriel_mymacro_body_tl { \\ }
}
% typeset the table
\begin{tabular}{c *{ \clist_count:n { #1 } } { |c } }
\tl_use:N \l__gabriel_mymacro_body_tl
\end{tabular}
}
\cs_new_protected:Nn \__gabriel_mymacro_add_entry:n
{
\tl_put_right:Nn \l__gabriel_mymacro_body_tl { & #1 }
}
\ExplSyntaxOff
\begin{document}
\mymacro{1,2,3}{A,B,C}{011,001}
\bigskip
\mymacro{Apple,Banana,Cherry,Date}{X,Apple,Banana,Cherry,Date}{
0000,0101,1111,1010
}
\end{document}
A variant with an optional argument to specify the column alignments.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% user interface
\NewDocumentCommand{\mymacro}{ommm}
{% #2 = column headers, #3 = row headers, #4 = entries
\IfNoValueTF { #1 }
{
\gabriel_mymacro:nnnn { c *{ \clist_count:n { #2 } } { |c } } { #2 } { #3 } { #4 }
}
{
\gabriel_mymacro:nnnn { #1 } { #2 } { #3 } { #4 }
}
}
% variables
\tl_new:N \l__gabriel_mymacro_body_tl
\tl_new:N \l__gabriel_mymacro_row_tl
\seq_new:N \l__gabriel_mymacro_entries_seq
% functions
\cs_new_protected:Nn \gabriel_mymacro:nnnn
{
% clear the tl containing the body and collect the entries
\tl_clear:N \l__gabriel_mymacro_body_tl
\seq_set_split:Nnn \l__gabriel_mymacro_entries_seq { , } { #4 }
% make the first row
\tl_put_right:Nx \l__gabriel_mymacro_body_tl
{
\clist_item:nn { #3 } { 1 }
}
\clist_map_function:nN { #2 } \__gabriel_mymacro_add_entry:n
\tl_put_right:Nn \l__gabriel_mymacro_body_tl { \\ \hline }
% build the following rows
\int_step_inline:nn { \clist_count:n { #3 } - 1 }
{
\tl_put_right:Nx \l__gabriel_mymacro_body_tl
{
\clist_item:nn { #3 } { ##1 + 1 }
}
\seq_pop_left:NN \l__gabriel_mymacro_entries_seq \l__gabriel_mymacro_row_tl
\tl_map_function:NN \l__gabriel_mymacro_row_tl \__gabriel_mymacro_add_entry:n
\tl_put_right:Nn \l__gabriel_mymacro_body_tl { \\ }
}
% typeset the table
\begin{tabular}{#1}
\tl_use:N \l__gabriel_mymacro_body_tl
\end{tabular}
}
\cs_new_protected:Nn \__gabriel_mymacro_add_entry:n
{
\tl_put_right:Nn \l__gabriel_mymacro_body_tl { & #1 }
}
\ExplSyntaxOff
\begin{document}
\mymacro{1,2,3}{A,B,C}{011,001}
\bigskip
\mymacro{Apple,Banana,Cherry,Date}{X,Apple,Banana,Cherry,Date}{
0000,0101,1111,1010
}
\bigskip
\mymacro[l|cccc]{Apple,Banana,Cherry,Date}{X,Apple,Banana,Cherry,Date}{
0000,0101,1111,1010
}
\end{document}