Working with clist indices in LaTeX3

Friends, I'm trying to port an old code of mine to a LaTeX3 implementation. Thanks to egreg, Joseph and David, I made a good progress! But then, I got stuck.

From the link above, I'm porting my songbook project. As you know, I have several indices for my songs, and I used to hardcode all of them beforehand. The code is not extensible without the need of adding more and more conditionals.

My idea: have a list (a comma separated list, or in L3 jargon, a clist) holding the index name and another list holding the abbreviation name. If I want to add, say, the word Hello world to an index with F as an abbreviation, I search the abbreviations list for the position of my item, then check its name counterpart.

From now on, the word index will be used to refer to an integer pointer that identifies an element of an array, and not the list of information we have in typography.

As usual, egreg saved the day and helped me with a L3 code to look for an item in a clist and return its index i. The code has the following approach:

• i > 0 : the first occurrence of the item in the clist. It's important to note that clist's indices start with 1 .
• i = 0 : the item is not found in the list.

I'm struggling with using the value from this lookup code in order to get the item from the other list, with \clist_item:Nn. Let's see some code:

% arara: pdflatex: { shell: on }
% arara: pdflatex
\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\usepackage{xparse}
\usepackage{imakeidx}

\ExplSyntaxOn

\clist_new:N \l_vozes_extensions_clist
\clist_new:N \l_vozes_abbreviations_clist
\int_new:N \l_vozes_index_step_int
\bool_new:N \l_vozes_index_found_bool

\cs_new:Npn \vozes_getitemindex:Nn #1 #2
{
\int_zero:N \l_vozes_index_step_int
\bool_set_false:N \l_vozes_index_found_bool
\clist_map_inline:Nn #1
{
\int_incr:N \l_vozes_index_step_int
\tl_if_eq:nnT { #2 } { ##1 }
{ \clist_map_break:n {  \bool_set_true:N \l_vozes_index_found_bool } }
}
\bool_if:NTF{ \l_vozes_index_found_bool }{ \int_to_arabic:n { \l_vozes_index_step_int } }{ 0 }
}

\cs_new:Npn \vozes_newthematicindex:nnnn #1 #2 #3 #4
{
\clist_put_right:Nn  \l_vozes_extensions_clist { #1 }
\clist_put_right:Nn \l_vozes_abbreviations_clist { #3 }
\makeindex[name=#1,title=#2,columns=#4]
}

\NewDocumentCommand{\newthematicindex}{ m m m m }{
\vozes_newthematicindex:nnnn { #1 }{ #2 }{ #3 }{ #4 }
}

\NewDocumentCommand{\thematicindex}{ m m }{
%\clist_item:Nn \l_vozes_extensions_clist {
% \vozes_getitemindex:Nn \l_vozes_abbreviations_clist { #1 }
%}
\index[ \clist_item:Nn \l_vozes_extensions_clist { 1 } ]{ #2 }
}

\NewDocumentCommand{\printthematicindex}{ m }{
%\clist_item:Nn \l_vozes_extensions_clist {
% \vozes_getitemindex:Nn \l_vozes_abbreviations_clist { #1 }
%}
\printindex[ \clist_item:Nn \l_vozes_extensions_clist { 1 } ]
}

\ExplSyntaxOff

\newthematicindex{ifoo}{The list of Foo}{F}{2}
\newthematicindex{ibar}{Bar is cool}{B}{2}
\newthematicindex{ifb}{Foo and Bar}{FB}{2}

\begin{document}

Hello.

\thematicindex{F}{Hello Foo}
\thematicindex{B}{Hello Bar}
\thematicindex{FB}{Hello Foobar}

\printthematicindex{F}
\printthematicindex{B}
\printthematicindex{FB}

\end{document}


Of course, this code doesn't work. :) The offending part is in the commented parts:

%\clist_item:Nn \l_vozes_extensions_clist {
% \vozes_getitemindex:Nn \l_vozes_abbreviations_clist { #1 }
%}


I'm lost with integer values. :( And speaking of which, I wonder how can I save the return of a command to a variable, should I use \def?

One last question: Is it good practice to mix L2 and L3? Should I \ExplSyntaxOff every time I have a L2 code, or there isn't any side effect?

Any enlightenment is appreciated. :)

-
You still thinking Java:) There is an easier solution with ONLY one list and can even be sorted see e.g. tex.stackexchange.com/a/15338/963 Use the power of TeX! –  Yiannis Lazarides Mar 27 '13 at 18:16
@Yiannis: forgive me, my friend, for I have sinned! :) I was not thinking on a HashMap. :P –  Paulo Cereda Mar 27 '13 at 18:35

\clist_item:Nn expects a number designation in its second argument, which \vozes_getitemindex:Nn doesn't provide, being it a set of instruction for providing an integer.

Here's a way out: you compute the integer and feed it to \clist_item:Nn. However, there's the glitch that \clist_item:Nn is not expandable; so sequences seem to be a better choice.

% arara: pdflatex: { shell: on }
% arara: pdflatex
\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\usepackage{xparse}
\usepackage{imakeidx}

\ExplSyntaxOn

\seq_new:N \g_vozes_extensions_seq
\seq_new:N \g_vozes_abbreviations_seq
\int_new:N \l_vozes_index_step_int
\bool_new:N \l_vozes_index_found_bool

\cs_new_protected:Npn \vozes_getitemindex:Nn #1 #2
{
\int_zero:N \l_vozes_index_step_int
\bool_set_false:N \l_vozes_index_found_bool
\seq_map_inline:Nn #1
{
\int_incr:N \l_vozes_index_step_int
\tl_if_eq:nnT { #2 } { ##1 }
{ \seq_map_break:n {  \bool_set_true:N \l_vozes_index_found_bool } }
}
\bool_if:NF{ \l_vozes_index_found_bool }{ \int_zero:N \l_vozes_index_step_int }
}

\cs_new_protected:Npn \vozes_newthematicindex:nnnn #1 #2 #3 #4
{
\seq_gput_right:Nn  \g_vozes_extensions_seq { #1 }
\seq_gput_right:Nn \g_vozes_abbreviations_seq { #3 }
\makeindex[name=#1,title=#2,columns=#4]
}

\NewDocumentCommand{\getitemindex}{mm}
{
\vozes_getitemindex:Nn #1 { #2 }
\int_to_arabic:n { \l_vozes_index_step_int }
}

\NewDocumentCommand{\newthematicindex}{ m m m m }{
\vozes_newthematicindex:nnnn { #1 }{ #2 }{ #3 }{ #4 }
}

\NewDocumentCommand{\thematicindex}{ m m }{
\vozes_getitemindex:Nn \g_vozes_abbreviations_seq { #1 }
\index[ \seq_item:Nn \g_vozes_extensions_seq { \l_vozes_index_step_int } ] { #2 }
}

\NewDocumentCommand{\printthematicindex}{ m }{
\vozes_getitemindex:Nn \g_vozes_abbreviations_seq { #1 }
\printindex[ \seq_item:Nn \g_vozes_extensions_seq { \l_vozes_index_step_int } ]
}

\ExplSyntaxOff

\newthematicindex{ifoo}{The list of Foo}{F}{2}
\newthematicindex{ibar}{Bar is cool}{B}{2}
\newthematicindex{ifb}{Foo and Bar}{FB}{2}

\begin{document}

Hello.

\thematicindex{F}{Hello Foo}
\thematicindex{B}{Hello Bar}
\thematicindex{FB}{Hello Foobar}

\printthematicindex{F}
\printthematicindex{B}
\printthematicindex{FB}

\end{document}


A more efficient implementation with property lists:

% arara: pdflatex
\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\usepackage{xparse}
\usepackage{imakeidx}

\ExplSyntaxOn

\prop_new:N \g_vozes_abbreviations_prop

\cs_new_protected:Npn \vozes_newthematicindex:nnnn #1 #2 #3 #4
{
\prop_gput:Nnn \g_vozes_abbreviations_prop { #3 } { #1 }
\makeindex[name=#1,title=#2,columns=#4]
}

\NewDocumentCommand{\newthematicindex}{ m m m m }
{
\vozes_newthematicindex:nnnn { #1 }{ #2 }{ #3 }{ #4 }
}

\NewDocumentCommand{\thematicindex}{ m m }
{
\index[ \prop_get:Nn \g_vozes_abbreviations_prop { #1 } ] { #2 }
}

\NewDocumentCommand{\printthematicindex}{ m }
{
\printindex[ \prop_get:Nn \g_vozes_abbreviations_prop { #1 } ]
}

\ExplSyntaxOff

\newthematicindex{ifoo}{The list of Foo}{F}{2}
\newthematicindex{ibar}{Bar is cool}{B}{2}
\newthematicindex{ifb}{Foo and Bar}{FB}{2}

\begin{document}

Hello.

\thematicindex{F}{Hello Foo}
\thematicindex{B}{Hello Bar}
\thematicindex{FB}{Hello Foobar}

\printthematicindex{F}
\printthematicindex{B}
\printthematicindex{FB}

\end{document}

-
Looking at the code, \clist_item:Nn is expandable, which is what I'd expect. I'll fix the description to reflect that. –  Joseph Wright Mar 27 '13 at 13:46
@JosephWright It is, but there's something puzzling: in that context I get \seq_item:Nn working, whereas \clist_item:Nn doesn't. I'll try again. –  egreg Mar 27 '13 at 15:10
Could be: these are 'experimental'. A demo would be handy (chat, LaTeX-L, etc.) –  Joseph Wright Mar 27 '13 at 15:36
@JosephWright and egreg: What do you think about the prob solution? I think this solution reflects best the issue of Paulo. –  Marco Daniel Mar 27 '13 at 18:42
Grazie mille, Enrico! :) –  Paulo Cereda Mar 28 '13 at 0:06