2

In this post, I need to implement a cycle of colors. My idea is to have a list of colors, to pop left a color and then push this color at the right. Here are some steps of use with a Python like syntax for the lists.

list     = [red,blue,orange,gray]
# Pop left
colpoped = red # To be used
list     = [blue,orange,gray]
# The color has to be pushed at the right.
list     = [blue,orange,gray,red]
...etc

Here is the piece of code I have tried to use but that does not work.

\seq_pop_left:NN \l__tnscalc_colors_seq \l__tnscalc_actual_color_temp_tl
...
\seq_push:Nn \l__tnscalc_colors_seq {\l__tnscalc_actual_color_temp_tl}

Any advice ?

Here is the full working code build with the help of the comment of Marcel K. below.

\documentclass{article}

\usepackage{nicematrix} \usepackage{tikz} \usetikzlibrary{fit}

\usepackage{tcolorbox} \tcbuselibrary{theorems}

% Sources % * https://tex.stackexchange.com/a/475291/6880 % * https://tex.stackexchange.com/a/558343/6880 % * https://tex.stackexchange.com/a/558185/6880

\newcommand\decoframe[3]{ \begin{tikzpicture}[remember picture, overlay] \node[draw = #1, rounded corners, thick, fit = (#2.north west) (#2.north east) (#3.south west) (#3.south east)] {}; \end{tikzpicture} }

\newcommand\decobox[1]{ \tcboxmath[colframe = red, left = 0mm, right = 0mm, top = 0mm, bottom = 0mm, boxsep = 1mm, ,boxrule = 1pt]{#1} }

\ExplSyntaxOn % Global variables used. \seq_new:N \l__tnscalc_colors_seq \tl_new:N \l__tnscalc_actual_color_temp_tl

\seq_new:N \l__tnscalc_calcexpval_seq
\seq_new:N \l__tnscalc_subseq_seq
\tl_new:N \l__tnscalc_xline_temp_tl
\tl_new:N \l__tnscalc_pline_temp_tl

\int_new:N \l__tnscalc_nbline_int
\int_new:N \l__tnscalc_numcol_int
\int_new:N \l__tnscalc_numcol_deco_int
\int_new:N \l__tnscalc_numcol_decotwo_int

% #1 : line separator % #2 : cell separator % #3 : content \NewDocumentCommand{\calcexpval}{O{red,blue,orange,gray} m m +m} { \tnscalc_calcexpval:nnnn{#1}{#2}{#3}{#4} }

% The internal version of the general purpose macro \cs_new_protected:Nn \tnscalc_calcexpval:nnnn { % #1 (option) : colors % #2 : line separator % #3 : cell separator % #4 : content

% Colors. \seq_set_split:Nnn \l__tnscalc_colors_seq { , } { #1 }

% Split into lines \seq_set_split:Nnn \l__tnscalc_calcexpval_seq { #2 } { #4 }

    \int_set:Nn \l__tnscalc_nbline_int { \seq_count:N \l__tnscalc_calcexpval_seq }

% Split each line into cells. \seq_pop_left:NN \l__tnscalc_calcexpval_seq \l__tnscalc_xline_temp_tl \seq_set_split:NnV \l__tnscalc_x_seq { #3 } \l__tnscalc_xline_temp_tl

    \seq_pop_left:NN \l__tnscalc_calcexpval_seq \l__tnscalc_pline_temp_tl
    \seq_set_split:NnV \l__tnscalc_p_seq { #3 } \l__tnscalc_pline_temp_tl

% Number of columns (offensive programming) \int_set:Nn \l__tnscalc_numcol_int { \seq_count:N \l__tnscalc_x_seq }

    \int_set:Nn \l__tnscalc_numcol_deco_int { 2 }

% The table of values
[%|{\int_use:N \l_mbc_N_int}{c} \begin{NiceArray}{r{\int_use:N \l__tnscalc_numcol_int}{|c}} x\sb{k} & \l__tnscalc_xline_temp_tl \ \hline p\sb{k} & \l__tnscalc_pline_temp_tl \CodeAfter
\int_add:Nn \l__tnscalc_numcol_int {2} \bool_while_do:nn { \int_compare_p:nNn \l__tnscalc_numcol_deco_int < \l__tnscalc_numcol_int }{ \seq_pop_left:NN \l__tnscalc_colors_seq \l__tnscalc_actual_color_temp_tl \seq_put_right:Nn \l__tnscalc_colors_seq {\l__tnscalc_actual_color_temp_tl} \decoframe{\l__tnscalc_actual_color_temp_tl}{1-\int_use:N \l__tnscalc_numcol_deco_int}{2-\int_use:N \l__tnscalc_numcol_deco_int}

                \int_add:Nn \l__tnscalc_numcol_deco_int {2}
            }
        \end{NiceArray}
    \]

% Explain the calculus of the expected value. \int_set:Nn \l__tnscalc_numcol_deco_int { 1 }

    $E(X) = \sum\limits\sb{k=1}^{\int_use:N \l__tnscalc_numcol_int} p\sb{k} \cdot x\sb{k}$

    \par

    $E(X) = 

    \bool_while_do:nn { \int_compare_p:nNn \l__tnscalc_numcol_int &gt; 0 }{
        \seq_pop_left:NN \l__tnscalc_x_seq \l__tnscalc_xval_tl
        \seq_pop_left:NN \l__tnscalc_p_seq \l__tnscalc_pval_tl

        \bool_if:NTF { \int_compare_p:nNn { \int_eval:n{ \int_mod:nn \l__tnscalc_numcol_deco_int 2} } = 1 }  { \decobox{\l__tnscalc_xval_tl \cdot \l__tnscalc_pval_tl} } { \l__tnscalc_xval_tl \cdot \l__tnscalc_pval_tl }

        \bool_if:NTF { \int_compare_p:nNn \l__tnscalc_numcol_int = 1 }  { } { + }

        \int_add:Nn \l__tnscalc_numcol_deco_int {1}
        \int_add:Nn \l__tnscalc_numcol_int {-1}
    }
    $
} 

\ExplSyntaxOff

\setlength\parindent{0pt}

\begin{document}

Let's try...

\calcexpval{\}{&}{ 0 & 1 & 2 & 3 & 4 \ 0.2000 & 0.2 & 0.4 & 0.05 & 0.15 }

With the default cycle of colors.

\calcexpval{\}{&}{ 0 & 1 \ 0.2000 & 0.2 }

With an odd number of columns and the cycle of colors \verb#blue,gray#.

\calcexpval[blue,gray]{\}{&}{ 0 & 1 & 2 \ 0.2000 & 0.2 & 0.4 }

With a single( ? ) column and the cycle of colors \verb#black#..

\calcexpval[black]{\}{&}{ 0 \ 0.2000 }

%With the short cycle of colors \verb#blue,red#..

\calcexpval[blue,red]{\}{&}{ 0 & 1 & 2 & 3 & 4 & 1 & 2 & 3 & 4 \ 0.2000 & 0.2 & 0.4 & 0.05 & 0.15 & 0.2 & 0.4 & 0.05 & 0.15 }

\end{document}

Bernard
  • 271,350
projetmbc
  • 13,315
  • 1
    I don't have the motivation right now to write a minimal example for you, but basically: Don't use \seq_push:Nn and \seq_pop_left:NN together (The stack functions like \seq_push:Nn should not be used with ordered functions like \seq_pop_list:NN) Instead, use \seq_put_right:Nn. Also, you want to use the value of the variable, not the variable itself, so use :NV instead of :Nn when inserting the value. – Marcel Krüger Aug 12 '20 at 12:25
  • @MarcelKrüger I have added the complete code and this works thanks to your advice. I will keep your advice in mind. – projetmbc Aug 12 '20 at 12:32
  • 1
    I see \bool_if:NTF { \int_compare_p:nNn \l__tnscalc_numcol_int = 1 } { } { + } in the code. This is not correct. You should put \bool_if:nTF (of, here, directly a \int_compare:nTF). – F. Pantigny Aug 12 '20 at 16:37
  • 1
    I see \seq_put_right:Nn \l__tnscalc_colors_seq {\l__tnscalc_actual_color_temp_tl} in the code. It's probably not what you want. You should put \seq_put_right:NV \l__tnscalc_colors_seq \l__tnscalc_actual_color_temp_tl – F. Pantigny Aug 12 '20 at 16:39
  • I am a real beginner. Thanks for pointing this. This is the first time I try to do some expl3 coding by my own. – projetmbc Aug 12 '20 at 16:47
  • If only there was a didactic book about expl3, that would be faster to learn some good practices. – projetmbc Aug 12 '20 at 16:53

1 Answers1

2

The error is in using \seq_put_right:Nn for reinserting the color at the end of the sequence. You need \seq_put_right:NV to add the contents of the token list variable.

However, there are many other enhancements to do.

For instance, you're abusing \int_use:N which is never necessary where an integer is expected. Also, \int_compare_p:nNn wants a braced argument, an unbraced one and another braced argument; but \int_compare_p:n is easier (and also more powerful, albeit being slightly slower; nothing to worry about).

Conditionals can be simplified and the multiple pops can be avoided by using \seq_map_indexed_inline:Nn.

\documentclass{article}

\usepackage{nicematrix} \usepackage{tikz} \usetikzlibrary{fit}

\usepackage{tcolorbox} \tcbuselibrary{theorems}

% Sources % * https://tex.stackexchange.com/a/475291/6880 % * https://tex.stackexchange.com/a/558343/6880 % * https://tex.stackexchange.com/a/558185/6880

\newcommand\decoframe[3]{% \begin{tikzpicture}[remember picture, overlay] \node[draw = #1, rounded corners, thick, fit = (#2.north west) (#2.north east) (#3.south west) (#3.south east)] {}; \end{tikzpicture}% }

\newcommand\decobox[1]{% \tcboxmath[colframe = red, left = 0mm, right = 0mm, top = 0mm, bottom = 0mm, boxsep = 1mm, ,boxrule = 1pt]{#1}% }

\ExplSyntaxOn % Global variables used. \seq_new:N \l__tnscalc_colors_seq \tl_new:N \l__tnscalc_actual_color_temp_tl

\seq_new:N \l__tnscalc_calcexpval_seq \seq_new:N \l__tnscalc_subseq_seq \tl_new:N \l__tnscalc_xline_temp_tl \tl_new:N \l__tnscalc_pline_temp_tl

\int_new:N \l__tnscalc_nbline_int \int_new:N \l__tnscalc_numcol_int \int_new:N \l__tnscalc_numcol_deco_int \int_new:N \l__tnscalc_numcol_decotwo_int

% #1 : line separator % #2 : cell separator % #3 : content \NewDocumentCommand{\calcexpval}{O{red,blue,orange,gray} m m +m} { \tnscalc_calcexpval:nnnn{#1}{#2}{#3}{#4} }

% The internal version of the general purpose macro \cs_new_protected:Nn \tnscalc_calcexpval:nnnn { % #1 (option) : colors % #2 : line separator % #3 : cell separator % #4 : content

% Colors. \seq_set_split:Nnn \l__tnscalc_colors_seq { , } { #1 }

% Split into lines \seq_set_split:Nnn \l__tnscalc_calcexpval_seq { #2 } { #4 } \int_set:Nn \l__tnscalc_nbline_int { \seq_count:N \l__tnscalc_calcexpval_seq }

% Split each line into cells. \seq_pop_left:NN \l__tnscalc_calcexpval_seq \l__tnscalc_xline_temp_tl \seq_set_split:NnV \l__tnscalc_x_seq { #3 } \l__tnscalc_xline_temp_tl

\seq_pop_left:NN \l__tnscalc_calcexpval_seq \l__tnscalc_pline_temp_tl \seq_set_split:NnV \l__tnscalc_p_seq { #3 } \l__tnscalc_pline_temp_tl

% Number of columns (offensive programming) \int_set:Nn \l__tnscalc_numcol_int { \seq_count:N \l__tnscalc_x_seq } \int_set:Nn \l__tnscalc_numcol_deco_int { 2 }

% The table of values
[ \begin{NiceArray}{r*{\l__tnscalc_numcol_int}{|c}} x\sb{k} & \l__tnscalc_xline_temp_tl \ \hline p\sb{k} & \l__tnscalc_pline_temp_tl \CodeAfter
\int_add:Nn \l__tnscalc_numcol_int {2} \bool_while_do:nn { \int_compare_p:n { \l__tnscalc_numcol_deco_int < \l__tnscalc_numcol_int } } { \seq_pop_left:NN \l__tnscalc_colors_seq \l__tnscalc_actual_color_temp_tl \seq_put_right:NV \l__tnscalc_colors_seq \l__tnscalc_actual_color_temp_tl \decoframe{\l__tnscalc_actual_color_temp_tl} {1-\int_use:N \l__tnscalc_numcol_deco_int} {2-\int_use:N \l__tnscalc_numcol_deco_int} \int_add:Nn \l__tnscalc_numcol_deco_int {2} } \end{NiceArray} ]

% Explain the calculus of the expected value. \int_set:Nn \l__tnscalc_numcol_deco_int { 1 }

$E(X) = \sum\limits\sb{k=1}^{\int_use:N \l__tnscalc_numcol_int} p\sb{k} \cdot x\sb{k}$ \par $E(X) = \seq_map_indexed_inline:Nn \l__tnscalc_x_seq { \seq_pop_left:NN \l__tnscalc_p_seq \l__tnscalc_pval_tl \int_if_odd:nTF { \l__tnscalc_numcol_deco_int } { \decobox{ ##2 \cdot \l__tnscalc_pval_tl} } { ##2 \cdot \l__tnscalc_pval_tl }

\int_compare:nT { ##1 &lt; \seq_count:N \l__tnscalc_x_seq } { + }
\int_add:Nn \l__tnscalc_numcol_deco_int {1}

} $ } \ExplSyntaxOff

\setlength\parindent{0pt}

\begin{document}

Let's try...

\calcexpval{\}{&}{ 0 & 1 & 2 & 3 & 4 \ 0.2000 & 0.2 & 0.4 & 0.05 & 0.15 }

With the default cycle of colors.

\calcexpval{\}{&}{ 0 & 1 \ 0.2000 & 0.2 }

With an odd number of columns and the cycle of colors \verb#blue,gray#.

\calcexpval[blue,gray]{\}{&}{ 0 & 1 & 2 \ 0.2000 & 0.2 & 0.4 }

With a single( ? ) column and the cycle of colors \verb#black#..

\calcexpval[black]{\}{&}{ 0 \ 0.2000 }

%With the short cycle of colors \verb#blue,red#..

\calcexpval[blue,red]{\}{&}{ 0 & 1 & 2 & 3 & 4 & 1 & 2 & 3 & 4 \ 0.2000 & 0.2 & 0.4 & 0.05 & 0.15 & 0.2 & 0.4 & 0.05 & 0.15 }

\end{document}

Sorry for the reformatting, but I can't see the braces with your indent style.

egreg
  • 1,121,712