1

I have this code with xparse package

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\addexercise}{m m m}
{
    \prop_gput:Nnn \g_exercise{ #1 } { {#2} {#3} }
}

\DeclareExpandableDocumentCommand{\Question}{m}
{
    \prop_get:NnNTF \g_exercise { #1 } \l_tmpa_tl
    {\tl_item:Nn \l_tmpa_tl { 1 }}
}

\DeclareExpandableDocumentCommand{\Solution}{m}
{
    \prop_get:NnNTF \g_exercise { #1 } \l_tmpa_tl
    {\tl_item:Nn \l_tmpa_tl { 2 }}
}

\prop_new:N \g_exercise
\ExplSyntaxOff

\addexercise
{01}
{
\textbf{Question 1}
}
{
\textbf{Solution 1}
}


\addexercise
{02}
{
\textbf{Question 2}
}
{
\textbf{Solution 2}
}



\begin{document}
    
    \section*{Exam} 
    \Question{01}
    \\
    \\
    \Solution{01}
    \\
    \\
    \\
    \Question{02}
    \\
    \\
    \Solution{02}   
    
\end{document}

enter image description here

How can I iterate over all question with something like a loop?. The quantity of question is variable. So I need to calculate it.

Thanks

1
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking.
    – Community Bot
    Jul 6, 2023 at 15:30

2 Answers 2

0

You can loop over the property list in the order of input if you store the keys in a sequence and loop over this one. I also suggest to store questions and solutions as different properties.

You still have the possibility of printing selected exercises and solutions.

It's recommended to use \NewDocumentCommand for parsing the arguments and pass them to an internal function. This way you can use the internal functions in several ways, like in the code below.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\addexercise}{m m m}
 {
  \exercise_add:nnn { #1 } { #2 } { #3 }
 }
\NewDocumentCommand{\Question}{m}
 {
  \exercise_question:n { #1 }
 }
\NewDocumentCommand{\Solution}{m}
 {
  \exercise_solution:n { #1 }
 }
\NewDocumentCommand{\printexercises}{}
 {
  \exercise_print:
 }

\prop_new:N \g_exercise_texts_prop
\seq_new:N \g_exercise_keys_seq

\cs_new_protected:Nn \exercise_add:nnn
 {
  \seq_gput_right:Nn \g_exercise_keys_seq { #1 }
  \prop_gput:Nnn \g_exercise_texts_prop { #1@text } { #2 }
  \prop_gput:Nnn \g_exercise_texts_prop { #1@sol } { #3 }
 }

\cs_new_protected:Nn \exercise_question:n
 {
  \prop_get:NnNT \g_exercise_texts_prop { #1@text } \l_tmpa_tl
   { \tl_use:N \l_tmpa_tl }
 }

\cs_new_protected:Nn \exercise_solution:n
 {
  \prop_get:NnNT \g_exercise_texts_prop { #1@sol } \l_tmpa_tl
   { \tl_use:N \l_tmpa_tl }
 }

\cs_new_protected:Nn \exercise_print:
 {
  \seq_map_function:NN \g_exercise_keys_seq \__exercise_print:n
 }

\cs_new_protected:Nn \__exercise_print:n
 {
  \noindent
  \exercise_question:n { #1 } \par
  \noindent
  \exercise_solution:n { #1 } \par
  \addvspace{\topsep}
 }

\ExplSyntaxOff

\addexercise{01}
  {\textbf{Question 1}}
  {\textbf{Solution 1}}


\addexercise{02}
  {\textbf{Question 2}}
  {\textbf{Solution 2}}



\begin{document}
    
\section*{Exam} 
\printexercises
  
\end{document}

enter image description here

With a little twist you can also select whether printing just the questions or also the solutions.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\addexercise}{m m m}
 {
  \exercise_add:nnn { #1 } { #2 } { #3 }
 }
\NewDocumentCommand{\Question}{m}
 {
  \exercise_question:n { #1 }
 }
\NewDocumentCommand{\Solution}{m}
 {
  \exercise_solution:n { #1 }
 }
\NewDocumentCommand{\printexercises}{s}
 {
  \IfBooleanTF{#1}
   {
    \bool_gset_true:N \g_exercise_showsol_bool
   }
   {
    \bool_gset_false:N \g_exercise_showsol_bool
   }
  \exercise_print:
 }

\prop_new:N \g_exercise_texts_prop
\seq_new:N \g_exercise_keys_seq
\bool_new:N \g_exercise_showsol_bool

\cs_new_protected:Nn \exercise_add:nnn
 {
  \seq_gput_right:Nn \g_exercise_keys_seq { #1 }
  \prop_gput:Nnn \g_exercise_texts_prop { #1@text } { #2 }
  \prop_gput:Nnn \g_exercise_texts_prop { #1@sol } { #3 }
 }

\cs_new_protected:Nn \exercise_question:n
 {
  \prop_get:NnNT \g_exercise_texts_prop { #1@text } \l_tmpa_tl
   { \tl_use:N \l_tmpa_tl }
 }

\cs_new_protected:Nn \exercise_solution:n
 {
  \prop_get:NnNT \g_exercise_texts_prop { #1@sol } \l_tmpa_tl
   { \tl_use:N \l_tmpa_tl }
 }

\cs_new_protected:Nn \exercise_print:
 {
  \seq_map_function:NN \g_exercise_keys_seq \__exercise_print:n
 }

\cs_new_protected:Nn \__exercise_print:n
 {
  \noindent
  \exercise_question:n { #1 } \par
  \bool_if:NT \g_exercise_showsol_bool
   {
    \noindent
    \exercise_solution:n { #1 } \par
   }
  \addvspace{\topsep}
 }

\ExplSyntaxOff

\addexercise{01}
  {\textbf{Question 1}}
  {\textbf{Solution 1}}

\addexercise{02}
  {\textbf{Question 2}}
  {\textbf{Solution 2}}

\addexercise{03}
  {\textbf{Question 3}}
  {\textbf{Solution 3}}

\addexercise{04}
  {\textbf{Question 4}}
  {\textbf{Solution 4}}



\begin{document}
    
\section*{Exam} 
\printexercises

\section*{Exam with solutions}

\printexercises*
  
\end{document}

enter image description here

A few final notes. The function \prop_get:NnNTF requires five arguments, but you only supplied four. Omit the F if you don't want to do special things if the key is not present.

Also \DeclareExpandableDocumentCommand should better be \NewExpandableDocumentCommand, but for this the internal functions used must all be expandable and \prop_get:NnN(TF) isn't. So you must use \NewDocumentCommand for it.

I renamed the variables according to the guidelines: \g_exercise is a bad name, for instance.

Loading xparse is no longer needed with current LaTeX.

0

You can use \prop_map_inline:Nn (or \prop_map_function:NN) to loop over a property list. Note however that property lists are not ordered, so you can't rely on the fact that you get the same order as you had when you filled your property list.

Inside \prop_map_inline:Nn you can use #1 to access the property's key and #2 to access its value.

Also, please note that your variables should follow expl3 naming convention which is \<scope>_<module>_<name>_<type>, in your case something like \g_user_exercise_prop.

Also please note that your \Question and \Answer are not expandable and therefore shouldn't use \DeclareExpandableDocumentCommand.

Also, while the following still uses \\ to get line breaks in the part of the document from your MWE, this is no good approach in LaTeX to get many line breaks, you should use \\ very seldomly (rule of thumb: only in tables to get the next row). Instead my print routine uses \par.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\prop_new:N \g_user_exercise_prop
\msg_new:nnn {user} {unknown-exercise}
  { No~ exercise~ with~ the~ name~ #1~ defined. }
\NewDocumentCommand{\addexercise}{m m m}
  {
    \prop_gput:Nnn \g_user_exercise_prop {#1} { {#2} {#3} }
  }

\cs_new_protected:Npn \__user_get_exercise:Nn #1#2
  {
    \prop_get:NnNTF \g_user_exercise_prop {#2} \l_tmpa_tl
      { \exp_after:wN #1 \l_tmpa_tl }
      { \msg_error:nnn {user} {unknown-exercise} {#2} }
  }

\NewDocumentCommand{\Question}{m}
  { \__user_get_exercise:Nn \use_i:nn {#1} }

\NewDocumentCommand{\Solution}{m}
  { \__user_get_exercise:Nn \use_ii:nn {#1} }

\NewExpandableDocumentCommand\UseQuestion {m} { \use_i:nn #1 }
\NewExpandableDocumentCommand\UseSolution {m} { \use_ii:nn #1 }

\NewDocumentCommand\MapExercises{+m}
  { \prop_map_inline:Nn \g_user_exercise_prop {#1} }
\ExplSyntaxOff

\addexercise{01}
  {\textbf{Question 1}}
  {\textbf{Solution 1}}


\addexercise{02}
  {\textbf{Question 2}}
  {\textbf{Solution 2}}



\begin{document}
    
\section*{Exam} 
\MapExercises{\noindent\UseQuestion{#2}\par\noindent\UseSolution{#2}\par}


    \Question{01}
    \\
    \\
    \Solution{01}
    \\
    \\
    \\
    \Question{02}
    \\
    \\
    \Solution{02}   
    
\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .