5

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.
<to be read again> 
                   \__int_eval:w 
l.34 \getitemswhile
1
  • 1
    Are you aware of \seq_map_inline:nn?
    – egreg
    Sep 23, 2016 at 8:04

2 Answers 2

6

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}
1
  • 1
    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.
    – Manuel
    Sep 23, 2016 at 11:48
5

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.

enter image description here

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}
2
  • 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?
    – TeXtnik
    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.
    – egreg
    Sep 26, 2016 at 13:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.