expl3: loop over a sequence with \int_do_while

I have a sequence where I get the elements by item number (needed for a macro don't show here). I am trying to iterate over the elements of the sequence in a do_while loop but I get an error about the integer comparison. I readed the interface3 document but can't find the problem.

MWE:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\DeclareDocumentCommand{\setlist}{}{
\seq_new:N \g_test_seq
\seq_gset_from_clist:Nn \g_test_seq {lin1, line2, line3}
}

\DeclareDocumentCommand{\insertdata}{m}{
\seq_item:Nn \g_test_seq #1
}

\DeclareDocumentCommand{\getitemswhile}{}{
\int_new:N \l_test_count
\int_set:Nn \l_test_count {\seq_count:N \g_test_seq}
\int_set:Nn \l_tmpa_int {1}

\int_do_while:nn {\l_tmpa_int < \l_test_count}
{
\insertdata{\int_use:N \l_tmpa_int}
\int_incr:N \l_tmpa_int
}
}

\ExplSyntaxOff

\begin{document}
\setlist
\getitemswhile
\end{document}


The error (running TexLive 2016 updated) reads:

?
! You can't use the character <' after \the.
<argument> <

l.34 \getitemswhile

?
! Missing = inserted for \ifnum.
\__int_eval:w
l.34 \getitemswhile

• Are you aware of \seq_map_inline:nn? Sep 23, 2016 at 8:04

Your problem is that you have

\seq_item:Nn \g_test_seq #1


and you should have

\seq_item:Nn \g_test_seq { #1 }


In any case, you have a weird mixture of user interface and programming layer in those definitions that you might want to address; also, declarations should be outside of commands; and also, you should adhere to the naming conventions (\l_test_int rather than \l_test_count).

\documentclass{scrartcl}
\usepackage{xparse}

\ExplSyntaxOn

\seq_new:N \g_test_seq
\DeclareDocumentCommand \setlist { }
{
\seq_gset_from_clist:Nn \g_test_seq { lin1 , line2 , line3 }
}

\DeclareDocumentCommand \insertdata { m }
{
\seq_item:Nn \g_test_seq { #1 }
}

\int_new:N \l_test_int
\DeclareDocumentCommand \getitemswhile { }
{
\int_set:Nn \l_test_int { \seq_count:N \g_test_seq }
\int_set:Nn \l_tmpa_int { 1 }
\int_do_while:nn { \l_tmpa_int < \l_test_int }
{
\insertdata { \int_use:N \l_tmpa_int }
\int_incr:N \l_tmpa_int
}
}

\ExplSyntaxOff

\begin{document}
\setlist
\getitemswhile
\end{document}

• The only thing that I haven't touched is the mixture between programming and interface. That's something that you should think about, I changed the other two small things. Sep 23, 2016 at 11:48

There are several tools in expl3 that can help in doing some task.

Use \seq_item:Nn only if you really need to; for doing something to all items in a sequence there are \seq_map_inline:Nn or \seq_map_function:NN.

Manuel, in his answer, has already pointed out some of the issues in your code; the main one is that declaration of variables should generally be outside definition of macros/functions.

It's of course possible to declare variables in a function, but do it only when such variables should be defined at runtime, with a name depending on current conditions.

Also you should not use \DeclareDocumentCommand, in general: this would overwrite any preceding definition of the same macro.

Here's a version with \seq_map_inline:Nn

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\setlist}{m}
{
\seq_gset_from_clist:Nn \g_textnik_test_seq { #1 }
}

\NewDocumentCommand{\getitems}{}
{
\seq_map_inline:Nn \g_textnik_test_seq
{
##1\par
}
}
\seq_new:N \g_textnik_test_seq
\ExplSyntaxOff

\begin{document}

\setlist{line1, line2, line3}

\getitems

\end{document}


You can see that the current item is passed to the mapping part as #1 (here ##1, because we're in a definition). You can do whatever you want to it, even passing it as the argument to another macro.

The same with \seq_map_function:NN

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\setlist}{m}
{
\seq_gset_from_clist:Nn \g_textnik_test_seq { #1 }
}

\NewDocumentCommand{\getitems}{}
{
\seq_map_function:NN \g_textnik_test_seq \textnik_dopar:n
}
\seq_new:N \g_textnik_test_seq
\cs_new_protected:Nn \textnik_dopar:n
{
#1\par
}
\ExplSyntaxOff

\begin{document}

\setlist{line1, line2, line3}

\getitems

\end{document}


In this case, each item is passed as the argument to the indicated one parameter function.

You can add the counter as well:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\setlist}{m}
{
\seq_gset_from_clist:Nn \g_textnik_test_seq { #1 }
}

\NewDocumentCommand{\getitems}{}
{
\int_zero:N \l_textnik_test_int
\seq_map_inline:Nn \g_textnik_test_seq
{
\int_incr:N \l_textnik_test_int
\int_to_arabic:n {\l_textnik_test_int}:~##1\par
}
}
\seq_new:N \g_textnik_test_seq
\int_new:N \l_textnik_test_int
\ExplSyntaxOff

\begin{document}

\setlist{line1, line2, line3}

\getitems

\end{document}

• I select the answer of @Manuel because it is the direct solution. I really needed the index of each item to do things not shown in the MWE. Thanks for your recommendations. Just one question: Why not define 'local' variables inside functions? Logically they belong there, isn't it? I know that they are not really 'local' or 'global' in TeX. Is the reason just perfromance? Sep 26, 2016 at 13:10
• @TeXtnik At each call of the function you'd allocate anew the variable, which is not a big deal for token lists or sequences, but it would be for integers. You can use \int_incr:N in the argument to \seq_map_inline:Nn` as well, no need to request the sequence item at each cycle. I added an example. Sep 26, 2016 at 13:14