# \ForEachX and string concatenation

I'm writing a class where I have an arbitrary number of strings that I'd like to concatenate, then loop over and typeset using \ForEachX from the forarray package. If I define a command to add to a string, something like:

\newcommand{\addtostring}[1]{\expandafter\def\expandafter\teststring\expandafter{\teststring {, }#1}}


And then try to break on comma, \ForEachX doesn't seem to recognise the commas to break on.

If instead, I define a command containing a similar string, there's no problem (see the MWE below). I suspect this has something to do with the \expandafter commands, but my understanding of how this command works is pretty fuzzy.

How can I set this up so that my \addtostring command allows an arbitrary number of comma-separated tokens to be strung together into something I can split on the comma with \ForEachX?

Here's the MWE:

\documentclass[10pt,a4paper]{article}
\usepackage{forarray}

\newcommand{\teststring}{}

\newcommand{\anotherteststring}{, Another string, to break}

\begin{document}

Test string: \teststring

\begin{itemize}
\ForEachX{,}{\item \thislevelitem}{\teststring}
\ForEachX{,}{\item \thislevelitem}{\anotherteststring}
\end{itemize}

\end{document}


I know this example is a bit artificial. \addtostring is a stub for a command that takes two arguments and produces a formatted string with them.

Also, I'm aware that the way I have this code set up I'll have an extra empty token at the start of the string. I can deal with that.

Remove the braces around the comma:

\documentclass[10pt,a4paper]{article}
\usepackage{forarray}

\newcommand{\teststring}{}
\expandafter\def\expandafter\teststring\expandafter{\teststring,#1}%
}

\newcommand{\anotherteststring}{, Another string, to break}

\begin{document}

Test string: \teststring

\begin{itemize}
\ForEachX{,}{\item \thislevelitem}{\teststring}
\ForEachX{,}{\item \thislevelitem}{\anotherteststring}
\end{itemize}

\end{document}


A better implementation with expl3 that uses sequences. The optional argument to \addtostring is for a “string name” (by default the name is “default”). Similarly for the optional argument to \usestring. Note that this has no side effect with commas at the beginning.

\documentclass[10pt,a4paper]{article}
\usepackage{xparse}

\ExplSyntaxOn
{
\seq_if_exist:cF { g_goblin_string_#1_seq }
{
\seq_new:c { g_goblin_string_#1_seq }
}
\seq_gput_right:cn { g_goblin_string_#1_seq } { #2 }
}

\NewDocumentCommand{\usestring}{O{default}m}
{
\seq_map_inline:cn { g_goblin_string_#1_seq } { #2 ##1 }
}
\ExplSyntaxOff

\begin{document}

\begin{itemize}
\usestring{\item}
\usestring[new]{\item}
\end{itemize}

\end{document}