# Make a CSV out of a \IfStrEqCase list

I have a macro \DefineStrEqCaseMacro which defines a macro that selects a value based on a parameter. With this, I am trying to replace the manual method:

\newcommand*{\SelectBasedOnValue}{beta}% Default Selector
\newcommand{\GreekSelector}[1][\SelectBasedOnValue]{%
\IfStrEqCase{#1}{%
{alpha}{\alpha}%
{beta}{\beta}%
{gamma}{\gamma}%
}[\chi]%
}%
%% Define this so we can step through the entire list of possible options
\csdef{GreekSelector List}{alpha, beta, gamma, <default>}%


with:

\DefineStrEqCaseMacro{GreekSelector}%
[\chi]% <-- Default value in case there is no match
{%
{alpha}{\alpha}%
{beta}{\beta}%
{gamma}{\gamma}%
}%


At the end I would like to be able to print ALL the possible values along with the default value (if any). The code below produces the desired result:

However, you notice that in \DefineStrEqCaseMacro, I have hard coded the list of possible values:

\IfValueTF{#2}{%
%% <> added to list ONLY if a default was specified}
\csdef{#1 List}{alpha, beta, gamma, <default>}%
}{%
\csdef{#1 List}{alpha, beta, gamma}%
}%


### Question:

How do I automatically define this \csdef{} based on #3 provided to this macro. This list should contain all the first options to each pair that \IfStrEqCase expects.

## Summary:

Given a parameter of the form:

    {alpha}{\alpha}%
{beta}{\beta}%
{gamma}{\gamma}%


with an arbitrary number of elements, how can I define a comma separated list so that I can step through each of the possible matches based on the first parameter in these pairs.

## Code:

\documentclass{article}
\usepackage{xstring}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{tikz}% for \foreach

\newcommand*{\SelectBasedOnValue}{beta}

\NewDocumentCommand\DefineStrEqCaseMacro{% Simplified from actual use case
m% #1 = macro name to define
o% #2 = default value in case of no match
m% #3 = IfStrEq case parameters
}{%
%% https://tex.stackexchange.com/q/226987/4301
\expandafter\NewDocumentCommand\csname#1\endcsname{%
s%                      #1 = NOT used here
O{\SelectBasedOnValue}% #2 = selector
}{%
\IfValueTF{#2}{%
\IfStrEqCase{##2}{%
#3%
}[#2]%
}{%
\IfStrEqCase{##2}{%
#3%
}[\PackageError{\jobname}{Unknown selector "##2"}]%
}%
}%
\IfValueTF{#2}{% ----- ??? How create this list defined here???
%% <default> added to list ONLY if a default was specified}
\csdef{#1 List}{alpha, beta, gamma, <default>}%
}{%
\csdef{#1 List}{alpha, beta, gamma}%
}%
}%

%%% ---------------------------------------------------------- Manual Method
%%% This is the manual way of doing things, but is error prone
%\newcommand{\GreekSelector}[1][\SelectBasedOnValue]{%
%    \IfStrEqCase{#1}{%
%        {alpha}{\alpha}%
%        {beta}{\beta}%
%        {gamma}{\gamma}%
%    }[\chi]%
%}%
Define this so we can step through the entire list of possible options
%\csdef{GreekSelector List}{alpha, beta, gamma, <default>}%
%%% ----------------------------------------------------------

%% ---------------------------------------------------------- Automated Method
\DefineStrEqCaseMacro{GreekSelector}%
[\chi]% <-- Default value in case there is no match
{%
{alpha}{\alpha}%
{beta}{\beta}%
{gamma}{\gamma}%
}%
%% ----------------------------------------------------------

\newcommand*{\TestGreekSelector}{%
Testing:
$\GreekSelector$, % <--- Select based on value of \SelectBasedOnValue
$\GreekSelector[alpha]$,
$\GreekSelector[Unknown]$.% <-- Select default case
}%

\newcommand*{\ShowAllPossibleValues}[1]{%
\par
List of ALL options of \texttt{\string#1}:\par
\edef\MyList{\csuse{#1 List}}%
\foreach \x in \MyList {
{\ttfamily\bfseries \x}: $\csuse{#1}[\x]$\par
}
}%

\begin{document}
%\TestGreekSelector
\ShowAllPossibleValues{GreekSelector}%
\end{document}


As usual, I wouldn't mix xparse, xstring and etoolbox, as xparse and expl3 already offer the needed tools.

\documentclass{article}
\usepackage{xparse}

\newcommand*{\SelectBasedOnValue}{beta}

\ExplSyntaxOn

% user level commands
\NewDocumentCommand{\defineselector}{mmm}
{
% #1 = command name to define, #2 = default, #3 = list to use
\grill_list_store:nnn { #1 } { #2 } { #3 }
\grill_list_define:nnn { #1 } { #2 } { #3 }
}

\NewDocumentCommand{\displayselector}{m+m}
{% #1 = selector name, #2 = template
\grill_list_display:nn { #1 } { #2 }
}

% internal functions
\cs_new_protected:Nn \grill_list_store:nnn
{
% massage the list and store it
\seq_gclear_new:c { g__grill_list_#1_seq }
\seq_gset_from_clist:cn { g__grill_list_#1_seq } { #3 }
\tl_gclear_new:c { g__grill_list_#1_tl }
\tl_gset:cx { g__grill_list_#1_tl }
{
\seq_use:cn { g__grill_list_#1_seq } {}
}
% store the default value
\tl_gclear_new:c { g__grill_list_#1_default_tl }
\tl_gset:cn { g__grill_list_#1_default_tl } { #2 }
}

\cs_new_protected:Nn \grill_list_define:nnn
{
% define the selector
\exp_args:Nc \NewDocumentCommand {#1}{O{\SelectBasedOnValue}}
{
\str_case_e:nvF { ##1 } { g__grill_list_#1_tl } { #2 }
}
}
\cs_generate_variant:Nn \str_case_e:nnF {nv}

\cs_new_protected:Nn \grill_list_display:nn
{
% set the auxiliary function to the template
\cs_set_protected:Nn \__grill_list_show:nn { #2 }
\par
List ~ of ~ all ~ options ~ for ~ #1 \par
\seq_map_inline:cn { g__grill_list_#1_seq }
{
\__grill_list_show:nn ##1
}
\__grill_list_show:nn { <default> } { \tl_use:c { g__grill_list_#1_default_tl } }
}

\ExplSyntaxOff

\defineselector{GreekSelector}{\chi}{
{alpha}{\alpha},
{beta}{\beta},
{gamma}{\gamma}
}

\begin{document}

$\GreekSelector$, % <--- Select based on value of \SelectBasedOnValue
$\GreekSelector[alpha]$,
$\GreekSelector[Unknown]$.% <-- Select default case

\displayselector{GreekSelector}{\texttt{#1}: $#2$\par}

\end{document}


The second argument to \displayselector is a template for doing the display, where #1 and #2 stand for the first item and the second item in each pair.

A fairly more general way to display the selector: change the definitions of \displayselector and \grill_list_display:nn to

\NewDocumentCommand{\displayselector}{m+m+m+m}
{% #1 = selector name, #2 = before, #3 = after, #4 = template
\grill_list_display:nnnn { #1 } { #2 } { #3 } { #4 }
}

\cs_new_protected:Nn \grill_list_display:nnnn
{
% trick to reuse the first argument
\cs_set_protected:Nn \__grill_list_before:n { #2 }
% set the auxiliary function to the template
\cs_set_protected:Nn \__grill_list_show:nn { #4 }
\__grill_list_before:n { #1 } % before
\seq_map_function:cN { g__grill_list_#1_seq } \__grill_list_unbrace:n
\__grill_list_show:nn { <default> } { \tl_use:c { g__grill_list_#1_default_tl } }
#3 % after
}
\cs_new:Nn \__grill_list_unbrace:n { \__grill_list_show:nn #1 }


Now you can call the display like

\displayselector{GreekSelector}
{List of options for #1\par
\begin{tabular}{@{}ll@{}}}
{\end{tabular}}
{\texttt{#1} & $#2$\\}


In the second argument you put what should precede the display, with #1 referring to the first argument (the selector name); in the third argument what should go after. The final argument is the template for each entry.

Complete code for completeness:

\documentclass{article}
\usepackage{xparse}

\newcommand*{\SelectBasedOnValue}{beta}

\ExplSyntaxOn

% user level commands
\NewDocumentCommand{\defineselector}{mmm}
{
% #1 = command name to define, #2 = default, #3 = list to use
\grill_list_store:nnn { #1 } { #2 } { #3 }
\grill_list_define:nnn { #1 } { #2 } { #3 }
}

\NewDocumentCommand{\displayselector}{m+m+m+m}
{% #1 = selector name, #2 = before, #3 = after, #4 = template
\grill_list_display:nnnn { #1 } { #2 } { #3 } { #4 }
}

% internal functions
\cs_new_protected:Nn \grill_list_store:nnn
{
% massage the list and store it
\seq_gclear_new:c { g__grill_list_#1_seq }
\seq_gset_from_clist:cn { g__grill_list_#1_seq } { #3 }
\tl_gclear_new:c { g__grill_list_#1_tl }
\tl_gset:cx { g__grill_list_#1_tl }
{
\seq_use:cn { g__grill_list_#1_seq } {}
}
% store the default value
\tl_gclear_new:c { g__grill_list_#1_default_tl }
\tl_gset:cn { g__grill_list_#1_default_tl } { #2 }
}

\cs_new_protected:Nn \grill_list_define:nnn
{
% define the selector
\exp_args:Nc \NewDocumentCommand {#1}{O{\SelectBasedOnValue}}
{
\str_case_e:nvF { ##1 } { g__grill_list_#1_tl } { #2 }
}
}
\cs_generate_variant:Nn \str_case_e:nnF {nv}

\cs_new_protected:Nn \grill_list_display:nnnn
{
% trick to reuse the first argument
\cs_set_protected:Nn \__grill_list_before:n { #2 }
% set the auxiliary function to the template
\cs_set_protected:Nn \__grill_list_show:nn { #4 }
\__grill_list_before:n { #1 } % before
\seq_map_function:cN { g__grill_list_#1_seq } \__grill_list_unbrace:n
\__grill_list_show:nn { <default> } { \tl_use:c { g__grill_list_#1_default_tl } }
#3 % after
}
\cs_new:Nn \__grill_list_unbrace:n { \__grill_list_show:nn #1 }

\ExplSyntaxOff

\defineselector{GreekSelector}{\chi}{
{alpha}{\alpha},
{beta}{\beta},
{gamma}{\gamma}
}

\begin{document}

$\GreekSelector$, % <--- Select based on value of \SelectBasedOnValue
$\GreekSelector[alpha]$,
$\GreekSelector[Unknown]$.% <-- Select default case

\displayselector{GreekSelector}
{List of options for #1\par
\begin{tabular}{@{}ll@{}}}
{\end{tabular}}
{\texttt{#1} & $#2$\\}

\end{document}


## Some explanations

The bulk of the code is \grill_list_store:nnn, where the comma separated list of pairs is massaged. I make a sequence out of it that will be used for the display and also for making a flat list, in the example case it will be

{alpha}{\alpha}{beta}{\beta}{gamma}{\gamma}


which is in the correct format for \str_case_e:nnF. This function should be called

\str_case_e:nnF { test string }
{
{case 1}{code}
{case 2}{code}
...
}
{ code for no match }


Here I use a variant \str_case_e:nvF, where the third argument is a token list name, precisely the flat list built before.

Thus I can define \GreekSelector as shown with \grill_list_define:nnn, passing the desired command name, the default to be used for no match, and the list of pairs.

The macro for displays is a bit tricky. In the simplified form the template is used to define an auxiliary function that's used in \seq_map_inline:cn, where the argument is used to select the massaged sequence.

I can offer routines \RemoveEveryKthElement and \UndelimitedListToCommaSpaceList which deliver the result (via \romannumeral-expansion) after two expansion-steps/after two \expandafter-chains.

\RemoveEveryKthElement does remove every K-th element from a list of undelimited (i.e. brace-nested) arguments.

You can, e.g., use it for removing every second element.

\UndelimitedListToCommaSpaceList does transform a list of undelimited arguments into a list where one level of surrounding braces is removed from each element and where as separator a comma and a space is attached behind each element but the last one.

\documentclass{article}
\usepackage{xstring}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{tikz}% for \foreach

\makeatletter
%%-----------------------------------------------------------------------------
%% Legal notes
%%.............................................................................
%% As portions of the compilable example which you are currently viewing
%% were delivered by Peter Grill, this work does not consist of the entire
%% compilable example you are currently viewing but it consists of everything
%% that within this example is nested between
%% a marker  %%<begin of copyrighted section>
%% and a marker  %%<end of copyrighted section>
%% regardless multiple/nested occurrences of such markers. ;-)
%%
%% Copyright (C) 2019 of this work by Ulrich Diez (eu_angelion@web.de)
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public Licence (LPPL), either
%% version 1.3 of this license or (at your option) any later
%% http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status 'not maintained'.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty - neither for probably included
%% documentation nor for any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
%%-----------------------------------------------------------------------------
%% Paraphernalia ;-) :
%%.............................................................................
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@exchange[2]{#2#1}%
\newcommand\UD@removespace{}\UD@firstoftwo{\def\UD@removespace}{} {}%
%%-----------------------------------------------------------------------------
%% 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:
%%.............................................................................
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
\UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a space-token
%%.............................................................................
%% \UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is a
%%                               space-token>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is not
%%                               a space-token>}%
\romannumeral0\UD@CheckWhetherNull{#1}%
{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
}%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@secondoftwo#1{}}%
{\UD@exchange{\UD@firstoftwo}}{\UD@exchange{\UD@secondoftwo}}%
{\UD@exchange{ }{\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter}\expandafter\expandafter
\expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%.............................................................................
%%   \UD@ExtractFirstArg{ABCDE} yields  {A}
%%
%%   \UD@ExtractFirstArg{{AB}CDE} yields  {AB}
%%
%% !!! \UD@ExtractFirstArg's argument must not be empty.     !!!
%%     (You can test for emptiness via \UD@CheckWhetherNull
%%      before applying \UD@ExtractFirstArg.)
%%.............................................................................
\newcommand\UD@RemoveTillUD@SelDOm{}%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
\newcommand\UD@ExtractFirstArg[1]{%
\romannumeral0%
\UD@ExtractFirstArgLoop{#1\UD@SelDOm}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
{ #1}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%-----------------------------------------------------------------------------
%% Remove every K-th element from list of undelimited/brace-nested arguments,
%% beginning with the L-th element.
%%.............................................................................
%% \RemoveEveryKthElement{<Number K>}%
%%                       {<Number L of the element to begin with>}%
%%                       {<List of undelimited arguments>}%
%%
%% In case <Number K> is smaller than 1 yields: <List of undelimited arguments>
%%   but with surplus space-tokens between elements removed.
%%   (K actually is an ordinal number.
%%   In the context of this macro it is unclear what is meant by non-positive
%%   ordinal numbers. Thus it is unclear what elements are to be removed from
%%   the list. Thus no elements are removed from the list. Only surplus space
%%   tokens between elements are removed from the list in this case.)
%% Else:
%%    In case <Number L of the element to begin with> is smaller than 1:
%%       Error-Message. (The problem with non-positive ordinal numbers
%%       again: A list of elements doesn't have a -1th or 0th
%%       element. So it is unclear what should be the starting-point for
%%       removing elements.)
%%   Else: <List of undelimited arguments> but with the
%%     L-th element and every K-th element following that element
%%     removed.
%%
%%   Caution:
%%   !!! There is no error-checking for detecting whether the arguments
%%        are numbers at all !!!
%%
%% Examples:
%%
%%   \RemoveEveryKthElement{-1}{-4}{{1}{2}{3}  {4}{5} {6} {7} {8} {9}{10}{11}{12}}
%%   yields: {1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}
%%
%%   \RemoveEveryKthElement{2}{-4}{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}}
%%   yields: Error-Message.
%%
%%   \RemoveEveryKthElement{4}{4}{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}}
%%   yields: {1}{2}{3}{5}{6}{7}{9}{10}{11}
%%
%%   \RemoveEveryKthElement{3}{6}{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}}
%%   yields: {1}{2}{3}{4}{5}{7}{8}{10}{11}
%%
%%   \RemoveEveryKthElement{2}{1}{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}}
%%   yields: {2}{4}{6}{8}{10}{12}
%%
%%   \RemoveEveryKthElement{2}{2}{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}}
%%   yields: {1}{3}{5}{7}{9}{11}
%%
%% Due to \romannumeral-expansion, the result is delivered after two
%% expansion-steps/\expandafter-chains
%%.............................................................................
\newcommand\RemoveEveryKthElement[3]{%
\romannumeral0%
\ifnum#1<1 \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\UD@UndelimitedListRemoveSpacesloop{#3}{}}{%
\ifnum#2<1 \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{ \@latex@error{\string\RemoveEveryKthElement: Value of <Number L of the element to begin with> is too small}%
{Value of <Number L of the element to begin with> must be positive.}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral0\UD@exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter\UD@firstoftwo\expandafter{\expandafter}%
\romannumeral0\number\number#2 000%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral0\UD@exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter\UD@firstoftwo\expandafter{\expandafter}%
\romannumeral0\number\number#1 000%
}{%
\UD@RemoveEveryKthElementLoop{}%
}%
}{#3}{}%
}%
}%
}%
\newcommand\UD@UndelimitedListRemoveSpacesloop[2]{%
\UD@CheckWhetherNull{#1}{ #2}{%
\expandafter\UD@UndelimitedListRemoveSpacesloop
\expandafter{\UD@removespace#1}{#2}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral0\UD@exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter\UD@PassFirstToSecond
\romannumeral0\UD@exchange{ }{\expandafter\expandafter\expandafter}%
\UD@ExtractFirstArg{#1}{#2}%
}{%
\expandafter\UD@UndelimitedListRemoveSpacesloop\expandafter{\UD@firstoftwo{}#1}%
}%
}%
}%
}%
\newcommand\UD@RemoveEveryKthElementLoop[5]{%
\UD@CheckWhetherNull{#4}{ #5}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\UD@removespace#4}{\UD@RemoveEveryKthElementLoop{#1}{#2}{#3}%
}{#5}%
}{%
\UD@CheckWhetherNull{#3}{%
\UD@CheckWhetherNull{#1}{%
\expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#4}{%
\UD@RemoveEveryKthElementLoop{#2}{#2}{}%
}{#5}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral0\UD@exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter\UD@PassFirstToSecond
\romannumeral0\UD@exchange{ }{\expandafter\expandafter\expandafter}%
\UD@ExtractFirstArg{#4}{#5}}{%
\expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#4}{%
\expandafter\UD@RemoveEveryKthElementLoop
\expandafter{\UD@firstoftwo{}#1}{#2}{}%
}%
}%
}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral0\UD@exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter\UD@PassFirstToSecond
\romannumeral0\UD@exchange{ }{\expandafter\expandafter\expandafter}%
\UD@ExtractFirstArg{#4}{#5}}{%
\expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#4}{%
\expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#3}{%
\UD@RemoveEveryKthElementLoop{}{#2}%
}%
}%
}%
}%
}%
}%
}%
%%-----------------------------------------------------------------------------
%% Turn list of undelimited arguments into comma-and-space-list by stripping
%% surrounding braces from each element and attaching a comma and a space
%% With the last element no comma and no space will be attached.
%%.............................................................................
%%
%%    \UD@UndelimitedListToCommaList{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}}
%% yields:
%%    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
%%
%% No warranties are given for what happens when the items within braces
%% contain commas ,too:
%%
%%    \UD@UndelimitedListToCommaList{{1}{2}{3}{4}{5, A, B, C}{6}{7}{8}{9}{10}{11}{12}}
%% yields:
%%    1, 2, 3, 4, 5, A, B, C, 6, 7, 8, 9, 10, 11, 12
\newcommand\UndelimitedListToCommaSpaceList[1]{%
\romannumeral0\UD@UndelimitedListToCommaSpaceListloop{#1}{}{}{, }%
}
\newcommand\UD@UndelimitedListToCommaSpaceListloop[4]{%
\UD@CheckWhetherNull{#1}{ #2}{%
\expandafter\UD@UndelimitedListToCommaSpaceListloop
\expandafter{%
\UD@removespace#1}{#2}{#3}{#4}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral0\UD@exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter\UD@exchange
\romannumeral0\UD@exchange{ }{\expandafter\expandafter\expandafter}%
\UD@ExtractFirstArg{#1}{#2#3}%
}{%
\expandafter\UD@UndelimitedListToCommaSpaceListloop\expandafter{\UD@firstoftwo{}#1}%
}{#4}{#4}%
}%
}%
}%
%%-----------------------------------------------------------------------------
\makeatother

\newcommand*{\SelectBasedOnValue}{beta}

\NewDocumentCommand\DefineStrEqCaseMacro{% Simplified from actual use case
m% #1 = macro name to define
o% #2 = default value in case of no match
m% #3 = IfStrEq case parameters
}{%
%% https://tex.stackexchange.com/q/226987/4301
\expandafter\NewDocumentCommand\csname#1\endcsname{%
s%                      #1 = NOT used here
O{\SelectBasedOnValue}% #2 = selector
}{%
\IfValueTF{#2}{%
\IfStrEqCase{##2}{%
#3%
}[#2]%
}{%
\IfStrEqCase{##2}{%
#3%
}[\PackageError{\jobname}{Unknown selector "##2"}]%
}%
}%
%%-- This is how one could probably create this list. ;-)
%% As you can define an option whose name is "<default>", I would
%% not add the default-value to the list but mention it separately.
%% Besides this one might specify emptiness as default.
%% Therefore I decided to have the macro #1default defined not in
%% terms of \long only when no value was specified.
%% For distinguising default being specified as emptiness from
%% default not being specified at all, compare the default-macro
%% to \empty.
%% Also I'd not use \csdef as that doesn't throw an error when
%% overriding a definition that already exists
\csname UD@PassFirstToSecond\expandafter\endcsname\expandafter{%
\romannumeral0%
\csuse{UD@exchange}{ }{%
\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter
}%
\expandafter\UndelimitedListToCommaSpaceList\expandafter{%
\romannumeral0\csuse{UD@exchange}{ }{%
\expandafter\expandafter\expandafter
}%
\RemoveEveryKthElement{2}{2}{#3}%
}%
}%
{\expandafter\newcommand\csname#1 List\endcsname}%
\IfValueTF{#2}%
{\expandafter\newcommand\csname#1 default\endcsname{#2}}%
{\expandafter\newcommand\expandafter*\csname#1 default\endcsname{}}%
}%

%% ---------------------------------------------------------- Automated Method
\DefineStrEqCaseMacro{GreekSelector}%
[\chi]% <-- Default value in case there is no match
{%
{alpha}{\alpha}%
{beta}{\beta}%
{gamma}{\gamma}%
}%
%% ----------------------------------------------------------

\newcommand*{\TestGreekSelector}{%
Testing:
$\GreekSelector$, % <--- Select based on value of \SelectBasedOnValue
$\GreekSelector[alpha]$,
$\GreekSelector[Unknown]$.% <-- Select default case
}%

\newcommand*{\ShowAllPossibleValues}[1]{%
\par\noindent
List of ALL options of \texttt{\string#1}:%
\edef\MyList{\csuse{#1 List}}%
\foreach \x in \MyList {%
\par\noindent
{\ttfamily\bfseries \x}: $\csuse{#1}[\x]$%
}%
\par\noindent
\hrulefill\null
\par\noindent
\textit{$\langle$standard-option$\rangle$}:
{\ttfamily\bfseries\SelectBasedOnValue}: $\csuse{#1}$%
\ifcsequal{#1 default}{empty}{}{%
\par\noindent
\textit{$\langle$default-value$\rangle$}: $\csuse{#1 default}$%
}%
\smallskip
\par\noindent
{\footnotesize
(The \textit{$\langle$standard-option$\rangle$} is used when the
user did not specify any option.\\%
The \textit{$\langle$standard-option$\rangle$} can be changed via
redefining the macro \texttt{\string\SelectBasedOnValue}.%
\ifcsequal{#1 default}{empty}{}{%
\\The \textit{$\langle$default-value$\rangle$} is used when
the user did specify an unknown option.%
}%
)%
}\par
}%

\begin{document}
\TestGreekSelector

\bigskip

\ShowAllPossibleValues{GreekSelector}%
\end{document}