# How to iterate over a comma separated list passed through the datatool interface

I'm trying to iterate over a comma separated list that is itself inside a cell in a .csv file, which I'm reading and iterating over with datatool.

As per, How do I process a comma separated list passed through a command, I thought the problem might be an expansion issue. But even putting the \foreach loop inside of a macro called \PROCESS and then using \expandafter does not seem to solve the problem.

Here's an MWE:

\begin{filecontents*}{verbs.csv}
Verb,Type
touch,EA
chase,EA
hear,ENA
see,ENA
\end{filecontents*}

\begin{filecontents*}{studies.csv}
Study,TestedAs,Verbs
fox1998,actional,"touch, chase"
fox1998,nonactional,"hear, see"
\end{filecontents*}

\documentclass{article}

\usepackage{booktabs}

\usepackage{xcolor}
\definecolor{darkred}{HTML}{B22613}

\newcommand*{\EA}[1]{\textcolor{darkred}{#1}}
\newcommand*{\ENA}[1]{\textcolor{cyan}{#1}}

\usepackage{pgffor}

\usepackage{datatool}

\newcommand*{\EAList}{}
\DTLforeach*[\DTLiseq{\Type}{EA}]{verbs}{\Verb=Verb,\Type=Type}{%
\expandafter\DTLifinlist\expandafter{\Verb}{\EAList}%
{}% do nothing if already in list
{% else add to list
\ifdefempty{\EAList}%
{\let\EAList\Verb}% first element of list
{% else append to list
\eappto\EAList{,\Verb}%
}%
}%
}%

\newcommand*{\ENAList}{}
\DTLforeach*[\DTLiseq{\Type}{ENA}]{verbs}{\Verb=Verb,\Type=Type}{%
\expandafter\DTLifinlist\expandafter{\Verb}{\ENAList}%
{}% do nothing if already in list
{% else add to list
\ifdefempty{\ENAList}%
{\let\ENAList\Verb}% first element of list
{% else append to list
\eappto\ENAList{,\Verb}%
}%
}%
}%

\newcommand*{\PROCESS}[1]{%
\foreach \x in {#1}{%
\DTLifinlist{\x}{\EAList}%
{% if in \EAList, print as \EA
\EA{\x}, %
}%
{% else, test for others
\DTLifinlist{\x}{\ENAList}%
{% if in \ENAList, print as \ENA
\ENA{\x}, %
}%
{% else print warning
D'oh.
}%
}%
}%
}%

\newcommand*{\PrintVerbs}[2]{%
\DTLforeach*[\DTLiseq{\Study}{#1}\and\DTLiseq{\TestedAs}{#2}]{studies}{%
\Study=Study,
\TestedAs=TestedAs,
\Verbs=Verbs%
}{%
\expandafter\PROCESS\expandafter{\Verbs}
}%
}%

\begin{document}

\begin{table}[htbp]
\begin{tabular}{ll}
\toprule
Study & Actional verbs tested\\
\midrule
Fox \& Grodzinsky (1998) & \PrintVerbs{fox1998}{actional}\\
\ldots & \ldots\\
\bottomrule
\end{tabular}
\end{table}

\begin{table}[htbp]
\begin{tabular}{ll}
\toprule
Study & Nonactional verbs tested\\
\midrule
Fox \& Grodzinsky (1998) & \PrintVerbs{fox1998}{nonactional}\\
\ldots & \ldots\\
\bottomrule
\end{tabular}
\end{table}

\end{document}


This produces:

But the expected output is:

I'll explain what's going on so that you don't have to try to decipher from just reading the code. There is a .csv file called verbs.csv which contains some verb type classifications for the different verbs in the list.

There have been some experiments that have tested these verbs but classified them in different ways (specifically, as either "actional" or "nonactional", rather than "EA" or "ENA").

So the type classifications given in verbs.csv are the classifications I want to use. I want to print each verb in a different color depending on how I would classify it, and not how it was previously classified.

So I first collect a list of the EA type verbs and then a list of the ENA type verbs.

Then, I want to iterate over the different studies, which have all tested different verbs. Depending on whether the verb is an EA type verb or an ENA type verb, I want to print it in a different color.

If the above code worked, one problem that I would still have is that there would be an extra comma. So if you also have suggestions on how to do something different for the last item in a comma separated list, that would be greatly appreciated, too. :)

I can offer an expl3 based solution.

\begin{filecontents*}{verbs.csv}
Verb,Type
touch,EA
chase,EA
hear,ENA
see,ENA
\end{filecontents*}

\begin{filecontents*}{studies.csv}
Study,TestedAs,Verbs
fox1998,actional,"touch, chase"
fox1998,nonactional,"hear, see"
\end{filecontents*}

\documentclass{article}

\usepackage{xparse}
\usepackage{booktabs}

\usepackage{xcolor}
\definecolor{darkred}{HTML}{B22613}

\newcommand*{\EA}[1]{\textcolor{darkred}{#1}}
\newcommand*{\ENA}[1]{\textcolor{cyan}{#1}}

\usepackage{pgffor}

\usepackage{datatool}

\ExplSyntaxOn
\seq_new:N \g_liter_ealist_seq
\seq_new:N \g_liter_enalist_seq
\seq_new:N \l_liter_temp_seq

\DTLforeach*[\DTLiseq{\Type}{EA}]{verbs}{\Verb=Verb,\Type=Type}
{
\seq_gput_right:Nx \g_liter_ealist_seq { \Verb }
}
\seq_gremove_duplicates:N \g_liter_ealist_seq

\DTLforeach*[\DTLiseq{\Type}{ENA}]{verbs}{\Verb=Verb,\Type=Type}
{
\seq_gput_right:Nx \g_liter_enalist_seq { \Verb }
}
\seq_gremove_duplicates:N \g_liter_enalist_seq

\cs_new_protected:Nn \liter_process:n
{
\seq_clear:N \l_liter_temp_seq
\clist_map_inline:nn { #1 }
{
\seq_if_in:NnTF \g_liter_ealist_seq { ##1 }
{
\seq_put_right:Nn \l_liter_temp_seq { \EA{##1} }
}
{
\seq_if_in:NnTF \g_liter_enalist_seq { ##1 }
{
\seq_put_right:Nn \l_liter_temp_seq { \ENA{##1} }
}
{
\seq_put_right:Nn \l_liter_temp_seq { D'oh }
}
}
}
\seq_use:Nn \l_liter_temp_seq { ,~ }
}
\cs_generate_variant:Nn \liter_process:n { V }

\NewDocumentCommand{\PrintVerbs}{mm}
{
\DTLforeach*[\DTLiseq{\Study}{#1}\and\DTLiseq{\TestedAs}{#2}]{studies}
{
\Study=Study,
\TestedAs=TestedAs,
\Verbs=Verbs
}
{
\liter_process:V \Verbs
}
}
\ExplSyntaxOff

\begin{document}

\begin{table}[htbp]
\begin{tabular}{ll}
\toprule
Study & Actional verbs tested\\
\midrule
Fox \& Grodzinsky (1998) & \PrintVerbs{fox1998}{actional}\\
\ldots & \ldots\\
\bottomrule
\end{tabular}
\end{table}

\begin{table}[htbp]
\begin{tabular}{ll}
\toprule
Study & Nonactional verbs tested\\
\midrule
Fox \& Grodzinsky (1998) & \PrintVerbs{fox1998}{nonactional}\\
\ldots & \ldots\\
\bottomrule
\end{tabular}
\end{table}

\end{document}


The EA and ENA lists are stored in sequences, with duplicates removed for efficiency. Then your \PROCESS macro does what you want, by building a sequence that's eventually “used” with comma-space as separator between items.