使用 xparse 迭代列表

使用 xparse 迭代列表

我有这个xparse带包的代码

\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}

在此处输入图片描述

我怎样才能用类似循环的方法遍历所有问题?问题的数量是可变的。所以我需要计算它。

谢谢

答案1

如果您按顺序存储键并循环遍历此键,则可以按输入顺序循环遍历属性列表。我还建议将问题和解决方案存储为不同的属性。

您仍然可以打印选定的练习和解决方案。

建议使用\NewDocumentCommand来解析参数并将其传递给内部函数。这样,​​您就可以以多种方式使用内部函数,如下面的代码所示。

\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}

在此处输入图片描述

只需稍加改动,您还可以选择是否仅打印问题还是也打印解决方案。

\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}

在此处输入图片描述

最后几点说明。该函数需要五个参数,但您只提供了四个。如果您不想在密钥不存在时执行特殊操作,\prop_get:NnNTF请省略。F

\DeclareExpandableDocumentCommand最好是\NewExpandableDocumentCommand,但为此使用的内部函数必须全部可扩展,而\prop_get:NnN(TF)并非如此。所以你必须使用\NewDocumentCommand它。

我根据指南重命名了变量:\g_exercise例如,是一个坏名字。

xparse当前的 LaTeX 不再需要加载。

答案2

您可以使用\prop_map_inline:Nn(或\prop_map_function:NN) 来循环遍历属性列表。但请注意,属性列表是无序的,因此您不能指望获得的顺序与您填写属性列表时的顺序相同。

\prop_map_inline:Nn您可以在里面使用#1它来访问属性的键并#2访问其值。

另请注意,您的变量应遵循expl3命名约定\<scope>_<module>_<name>_<type>,在您的情况下类似于\g_user_exercise_prop

另请注意,您的\Question\Answer不可扩展,因此不应使用\DeclareExpandableDocumentCommand

此外,虽然以下内容仍可用于\\从 MWE 获取文档部分的换行符,但这并不是在 LaTeX 中获取大量换行符的好方法,您应该\\很少使用(经验法则:仅在表格中获取下一行)。相反,我的打印例程使用\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}

在此处输入图片描述

相关内容