I can offer a macro \KeepKthOfLArguments
which picks the K-th undelimited argument of a list of L undelimited arguments.
When doing macro-programming, you can implement a "mechanism" where the L arguments are gathered and accumulated within a single macro argument which in turn holds the list of L arguments and which in turn is passed to an internal macro which in turn does things in terms of \KeepKthOfLArguments
.
I don't recommend using this for macros at user-level.
At user-level I recommend interfaces that do list-processing, e.g., with keyval-syntax. (keyval-syntax implies processing a comma-separated list of key=value-pairs.)
Things like \pgfplotstableread
of the package pgfplots and the facilities of the package datatool for iterating on databases and comma-lists and property-lists of expl3 might be of interest as well.
But sometimes I use such things with macros that both generate and process large lists of undelimited arguments automatically without the need of the user passing/typing these arguments.
\documentclass{article}
\makeatletter
%% Code for \KeepKthOfLArguments:
%%=============================================================================
%% Paraphernalia:
%% \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond,
%% \UD@stopromannumeral, \UD@CheckWhetherNull
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%-----------------------------------------------------------------------------
%% 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\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}{%
\expandafter\UD@stopromannumeral\UD@firstoftwo}%
}%
%%=============================================================================
%% Keep only the K-th of L consecutive undelimited arguments.
%% ( IF K < 1 OR K > L just remove L consecutive undelimited arguments. )
%%=============================================================================
%% \KeepKthOfLArguments{<integer number K>}%
%% {<integer number L>}%
%% <sequence of L consecutive undelimited arguments>
%%
%% If L < 1 yields nothing.
%% Else:
%% If K >= 1 and K < L yields:
%% <K-th undelimited argument from <sequence of L consecutive undelimited
%% arguments>>
%% If K < 1 or K > L
%% (-> there is no K-th argument in the
%% <sequence of L consecutive undelimited arguments> )
%% yields nothing but removal of <sequence of L consecutive
%% undelimited arguments>
\newcommand\KeepKthOfLArguments[2]{%
\romannumeral
% #1: <integer number K>
% #2: <integer number L>
\expandafter\UD@KeepKthOfLArgumentsKSmallerOneFork
\expandafter{\romannumeral\number\number#1 000\expandafter}%
\expandafter{\romannumeral\number\number#2 000}%
}%
%%-----------------------------------------------------------------------------
\newcommand\UD@KeepKthOfLArgumentsKSmallerOneFork[2]{%
% #1: <K letters m>
% #2: <L letters m >
\UD@CheckWhetherNull{#1}{% K is smaller than one:
\UD@KeepKthOfLArgumentsRemoveNArguments{#2}{\UD@stopromannumeral}{}%
}{% K is not smaller than one:
\expandafter\UD@PassFirstToSecond
\expandafter{%
\UD@firstoftwo{}#1%
}{%
\UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop{#1}{#2}%
}{#2}%
}%
}%
%%-----------------------------------------------------------------------------
\newcommand\UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop[4]{%
% #1: <K letters m>
% #2: <L letters m>
% (For detecting whether K>L or K<=L, during the loop letters m will
% be removed both from #1 and #2 until at least one of these arguments
% is empty.
% When the loop terminates with 0<K<=L, #1 will be empty and #2
% will hold an amount of letters m corresponding to the the
% difference L-K.
% When the loop terminates with K>L, #1 will not be empty and #2
% will be empty.
% )
% #3: <K-1 letters m>
% #4: <L letters m>
% (#3 and #4 will be left untouched during the loop so they can be
% used for performing appropriate action when loop terminates as
% it is known whether K>L.)
\UD@CheckWhetherNull{#1}{% We have K<=L:
\UD@KeepKthOfLArgumentsRemoveNArguments{%
#3%
}{%
\UD@KeepKthOfLArgumentsRemoveNArguments{#2}{\UD@stopromannumeral}%
}{}%
}{%
\UD@CheckWhetherNull{#2}{% We have K>L:
\UD@KeepKthOfLArgumentsRemoveNArguments{#4}{\UD@stopromannumeral}{}%
}{% We don't know yet whether K<=L or K>L, thus remove letters m and
% do another iteration:
\expandafter\UD@PassFirstToSecond
\expandafter{%
\UD@firstoftwo{}#2%
}{%
\expandafter\UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop
\expandafter{%
\UD@firstoftwo{}#1%
}%
}{#3}{#4}%
}%
}%
}%
%%-----------------------------------------------------------------------------
%% \UD@KeepKthOfLArgumentsRemoveNArguments{<N letters m>}%
%% {<argument 1>}%
%% {<argument 2>}%
%% <sequence of consecutive
%% undelimited arguments>
%%.............................................................................
%% Removes the first N undelimited arguments from the <sequence of
%% consecutive undelimited arguments>, then inserts
%% <argument 1><argument 2>
%%
%% On the one hand when providing <argument 2> empty, you can use
%% <argument 1> for nesting calls to \UD@KeepKthOfLArgumentsRemoveNArguments.
%% On the other hand you can provide a <space token> for stopping
%% \romannumeral-expansion as <argument 1> and have the
%% macro grab the <K-th undelimited argument> from the <sequence of L
%% consecutive undelimited arguments> as <argument 2>.
%%
\newcommand\UD@KeepKthOfLArgumentsRemoveNArguments[3]{%
%% #1: <N letters m>
%% #2: <Argument 1>
%% #3: <Argument 2>
\UD@CheckWhetherNull{#1}{#2#3}{%
\UD@firstoftwo{%
\expandafter\UD@KeepKthOfLArgumentsRemoveNArguments
\expandafter{%
\UD@firstoftwo{}#1%
}{#2}{#3}%
}%
}%
}%
%%-----------------------------------------------------------------------------
%% End of code for \KeepKthOfLArguments.
\makeatother
\newcommand\MacroWithThirtyNestedParameters[1]{%
This is paramter 1: \textbf{\KeepKthOfLArguments{1}{30}#1}\\
This is paramter 2: \textbf{\KeepKthOfLArguments{2}{30}#1}\\
This is paramter 3: \textbf{\KeepKthOfLArguments{3}{30}#1}\\
This is paramter 4: \textbf{\KeepKthOfLArguments{4}{30}#1}\\
This is paramter 5: \textbf{\KeepKthOfLArguments{5}{30}#1}\\
This is paramter 6: \textbf{\KeepKthOfLArguments{6}{30}#1}\\
This is paramter 7: \textbf{\KeepKthOfLArguments{7}{30}#1}\\
This is paramter 8: \textbf{\KeepKthOfLArguments{8}{30}#1}\\
This is paramter 9: \textbf{\KeepKthOfLArguments{9}{30}#1}\\
This is paramter 10: \textbf{\KeepKthOfLArguments{10}{30}#1}\\
This is paramter 11: \textbf{\KeepKthOfLArguments{11}{30}#1}\\
This is paramter 12: \textbf{\KeepKthOfLArguments{12}{30}#1}\\
This is paramter 13: \textbf{\KeepKthOfLArguments{13}{30}#1}\\
This is paramter 14: \textbf{\KeepKthOfLArguments{14}{30}#1}\\
This is paramter 15: \textbf{\KeepKthOfLArguments{15}{30}#1}\\
This is paramter 16: \textbf{\KeepKthOfLArguments{16}{30}#1}\\
This is paramter 17: \textbf{\KeepKthOfLArguments{17}{30}#1}\\
This is paramter 18: \textbf{\KeepKthOfLArguments{18}{30}#1}\\
This is paramter 19: \textbf{\KeepKthOfLArguments{19}{30}#1}\\
This is paramter 20: \textbf{\KeepKthOfLArguments{20}{30}#1}\\
This is paramter 21: \textbf{\KeepKthOfLArguments{21}{30}#1}\\
This is paramter 22: \textbf{\KeepKthOfLArguments{22}{30}#1}\\
This is paramter 23: \textbf{\KeepKthOfLArguments{23}{30}#1}\\
This is paramter 24: \textbf{\KeepKthOfLArguments{24}{30}#1}\\
This is paramter 25: \textbf{\KeepKthOfLArguments{25}{30}#1}\\
This is paramter 26: \textbf{\KeepKthOfLArguments{26}{30}#1}\\
This is paramter 27: \textbf{\KeepKthOfLArguments{27}{30}#1}\\
This is paramter 28: \textbf{\KeepKthOfLArguments{28}{30}#1}\\
This is paramter 29: \textbf{\KeepKthOfLArguments{29}{30}#1}\\
This is paramter 30: \textbf{\KeepKthOfLArguments{30}{30}#1}%
}%
\begin{document}
\noindent
\MacroWithThirtyNestedParameters{%
{Word 1}%
{Word 2}%
{Word 3}%
{Word 4}%
{Word 5}%
{Word 6}%
{Word 7}%
{Word 8}%
{Word 9}%
{Word 10}%
{Word 11}%
{Word 12}%
{Word 13}%
{Word 14}%
{Word 15}%
{Word 16}%
{Word 17}%
{Word 18}%
{Word 19}%
{Word 20}%
{Word 21}%
{Word 22}%
{Word 23}%
{Word 24}%
{Word 25}%
{Word 26}%
{Word 27}%
{Word 28}%
{Word 29}%
{Word 30}%
}%
\vfill
\noindent\verb|\KeepKthOfLArguments| does deliver the result after two
expansion-steps:
\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
\KeepKthOfLArguments{3}{11}{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}%
}%
\end{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
\KeepKthOfLArguments{3}{11}{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}%
}%
\noindent\texttt{\string\test: \meaning\test}%
\vfill\vfill
\end{document}

In case you don't like to specify the amount of undelimited arguments but only which one to pick, if present, I can offer a macro \ExtractKthArg
.
When doing macro-programming, you can pass an arbitrary sequence of undelimited arguments via nesting that sequence into a single undelimited macro argument and apply \ExtractKthArg
on that single argument for extracting a specific element from the sequence.
\documentclass{article}
\makeatletter
%% Code for \ExtractKthArg
%%=============================================================================
%% Paraphernalia:
%% \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond, \UD@Exchange,
%% \UD@stopromannumeral, \UD@CheckWhetherNull
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%-----------------------------------------------------------------------------
%% 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\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}{%
\expandafter\UD@stopromannumeral\UD@firstoftwo}%
}%
%%=============================================================================
%% Extract K-th inner undelimited argument:
%%
%% \ExtractKthArg{<integer K>}%
%% {<tokens in case list of undelimited args doesn't have a k-th argumnent>}%
%% {<list of undelimited args>} %
%%
%% In case there is no K-th argument in <list of indelimited args> :
%% Does deliver <tokens in case list of undelimited args doesn't have a k-th argumnent.
%% In case there is a K-th argument in <list of indelimited args> :
%% Does deliver that K-th argument with one level of braces removed.
%%
%% Examples:
%%
%% \ExtractKthArg{0}{not available}{ABCDE} yields: not available
%%
%% \ExtractKthArg{3}{not available}{ABCDE} yields: C
%%
%% \ExtractKthArg{3}{not available}{AB{CD}E} yields: CD
%%
%% \ExtractKthArg{4}{not available}{{001}{002}{003}{004}{005}} yields: 004
%%
%% \ExtractKthArg{6}{not available}{{001}{002}{003}} yields: not available
%%
%%=============================================================================
\newcommand\ExtractKthArg[2]{%
\romannumeral%
% #1: <integer number K>
% #2: <action if there is no K-th argument>
\expandafter\UD@ExtractKthArgCheck
\expandafter{\romannumeral\number\number#1 000}{#2}%
}%
\newcommand\UD@ExtractKthArgCheck[3]{%
\UD@CheckWhetherNull{#1}{\UD@stopromannumeral#2}{% empty
\expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}#1}{#2}{#3}%
}%
}%
\begingroup
\def\UD@ExtractFirstArgLoop#1{%
\endgroup
\@ifdefinable\UD@RemoveTillFrozenrelax{%
\long\def\UD@RemoveTillFrozenrelax##1##2#1{{##1}}%
}%
\newcommand\UD@ExtractKthArgLoop[3]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo##3{}.}{\UD@stopromannumeral##2}{%
\UD@CheckWhetherNull{##1}{%
\UD@ExtractFirstArgLoop{##3#1}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}##3}%
{\expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}##1}{##2}}%
}%
}%
}%
}%
\expandafter\expandafter\expandafter\UD@ExtractFirstArgLoop
\expandafter\expandafter\expandafter{%
\expandafter\expandafter\ifnum0=0\fi}%
%% Usage of frozen-\relax as delimiter is for speeding things up by reducing the
%% amount of iterations needed. I chose frozen-\relax because David Carlisle
%% pointed out in <https://tex.stackexchange.com/a/578877>
%% that frozen-\relax cannot be (re)defined in terms of \outer and cannot be
%% affected by \uppercase/\lowercase.
%%
%% \UD@ExtractFirstArg's argument may contain frozen-\relax:
%% The only effect is that internally more iterations are needed for
%% obtaining the result.
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
{\expandafter\UD@stopromannumeral\UD@firstoftwo#1{}}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillFrozenrelax#1}}%
}%
%% End of code for \ExtractKthArg.
\makeatother
\newcommand\MacroWithThirtyNestedParameters[1]{%
This is paramter 1: \textbf{\ExtractKthArg{1}{not available}{#1}}\\
This is paramter 2: \textbf{\ExtractKthArg{2}{not available}{#1}}\\
This is paramter 3: \textbf{\ExtractKthArg{3}{not available}{#1}}\\
This is paramter 4: \textbf{\ExtractKthArg{4}{not available}{#1}}\\
This is paramter 5: \textbf{\ExtractKthArg{5}{not available}{#1}}\\
This is paramter 6: \textbf{\ExtractKthArg{6}{not available}{#1}}\\
This is paramter 7: \textbf{\ExtractKthArg{7}{not available}{#1}}\\
This is paramter 8: \textbf{\ExtractKthArg{8}{not available}{#1}}\\
This is paramter 9: \textbf{\ExtractKthArg{9}{not available}{#1}}\\
This is paramter 10: \textbf{\ExtractKthArg{10}{not available}{#1}}\\
This is paramter 11: \textbf{\ExtractKthArg{11}{not available}{#1}}\\
This is paramter 12: \textbf{\ExtractKthArg{12}{not available}{#1}}\\
This is paramter 13: \textbf{\ExtractKthArg{13}{not available}{#1}}\\
This is paramter 14: \textbf{\ExtractKthArg{14}{not available}{#1}}\\
This is paramter 15: \textbf{\ExtractKthArg{15}{not available}{#1}}\\
This is paramter 16: \textbf{\ExtractKthArg{16}{not available}{#1}}\\
This is paramter 17: \textbf{\ExtractKthArg{17}{not available}{#1}}\\
This is paramter 18: \textbf{\ExtractKthArg{18}{not available}{#1}}\\
This is paramter 19: \textbf{\ExtractKthArg{19}{not available}{#1}}\\
This is paramter 20: \textbf{\ExtractKthArg{20}{not available}{#1}}\\
This is paramter 21: \textbf{\ExtractKthArg{21}{not available}{#1}}\\
This is paramter 22: \textbf{\ExtractKthArg{22}{not available}{#1}}\\
This is paramter 23: \textbf{\ExtractKthArg{23}{not available}{#1}}\\
This is paramter 24: \textbf{\ExtractKthArg{24}{not available}{#1}}\\
This is paramter 25: \textbf{\ExtractKthArg{25}{not available}{#1}}\\
This is paramter 26: \textbf{\ExtractKthArg{26}{not available}{#1}}\\
This is paramter 27: \textbf{\ExtractKthArg{27}{not available}{#1}}\\
This is paramter 28: \textbf{\ExtractKthArg{28}{not available}{#1}}\\
This is paramter 29: \textbf{\ExtractKthArg{29}{not available}{#1}}\\
This is paramter 30: \textbf{\ExtractKthArg{30}{not available}{#1}}%
}%
\pagestyle{empty}
\begin{document}
\vspace*{-1in}\enlargethispage{1in}
\noindent\verb|\ExtractKthArg{-1}{not available}{ABCDE}|: \ExtractKthArg{-1}{not available}{ABCDE}\\
\verb|\ExtractKthArg{0}{not available}{ABCDE}|: \ExtractKthArg{0}{not available}{ABCDE}\\
\verb|\ExtractKthArg{1}{not available}{ABCDE}|: \ExtractKthArg{1}{not available}{ABCDE}\\
\verb|\ExtractKthArg{2}{not available}{ABCDE}|: \ExtractKthArg{2}{not available}{ABCDE}\\
\verb|\ExtractKthArg{3}{not available}{ABCDE}|: \ExtractKthArg{3}{not available}{ABCDE}\\
\verb|\ExtractKthArg{4}{not available}{ABCDE}|: \ExtractKthArg{4}{not available}{ABCDE}\\
\verb|\ExtractKthArg{5}{not available}{ABCDE}|: \ExtractKthArg{5}{not available}{ABCDE}\\
\verb|\ExtractKthArg{6}{not available}{ABCDE}|: \ExtractKthArg{6}{not available}{ABCDE}
\vfill
\noindent
\MacroWithThirtyNestedParameters{%
{Word 1}%
{Word 2}%
{Word 3}%
{Word 4}%
{Word 5}%
{Word 6}%
{Word 7}%
{Word 8}%
{Word 9}%
{Word 10}%
{Word 11}%
{Word 12}%
{Word 13}%
{Word 14}%
{Word 15}%
{Word 16}%
{Word 17}%
{Word 18}%
{Word 19}%
{Word 20}%
{Word 21}%
{Word 22}%
{Word 23}%
{Word 24}%
{Word 25}%
{Word 26}%
{Word 27}%
{Word 28}%
{Word 29}%
{Word 30}%
}%
\vfill
\noindent\verb|\ExtractKthArg| does deliver the result after two
expansion-steps:
\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
\ExtractKthArg{3}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}}%
}%
\end{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
\ExtractKthArg{3}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}}%
}%
\noindent\texttt{\string\test: \meaning\test}%
\vfill\vfill
\end{document}

With both examples everything works by means of expansion only. No temporary macros get defined from arguments. This implies that the arguments themselves can contain hashes. E.g., things like #1
don't yield error-messages as would be the case when "naively" defining temporary macros in terms of \def
from such arguments. This also implies that arguments can contain consecutive hashes, e.g., ##
, without them being reduced to a single hash #
as would be the case at the time of expanding temporary macros defined from such arguments.
I recommend to use such things at best when list-processing-interfaces, e.g. key=value-interfaces, and processing of databases/data tables by means of pgfplots or datatool are not possible, and when furthermore the use of the many arguments is so interwoven that it is not possible to split the thing into several macros each of which grabs/processes only a subset of the arguments consisting of less than 10 arguments.
In practice, I have never encountered the latter not being possible.