Uma continuação deminha pergunta anteriorrespondido graças a @egreg. (Talvez o Prof. Gregorio possa me ajudar aqui também.)
Situação
Estou criando uma macro Tabela de Perguntas (ToQ) para criar uma tabela de notas na capa de um exame ou tarefa. Estava funcionando bem, tabular
mas mudei para o Tabularray tblr
, pelo qual estou me apaixonando. Infelizmente, como costumo totcount
criar contadores para as notas em cada nova questão à medida que elas são encontradas, me deparo com questões de expansão que hoje me deixam perplexo.
Problema
Loops não podem ser colocados dentro de um tblr
ambiente (veja§3.2.3do manual), como é o caso dos tabulares comuns. Mas as soluções que parecem funcionar para tabelas comuns:
- usando loops primitivos LaTeX,
- construindo o corpo fora da mesa como um \gdef feito de \edefs, e
- construindo o corpo como um registro de token,
não trabalhei para tblr
. Além disso, tblr
permite especificar uma expand
opção para especificar tokens para expansão antes de processar o corpo. (Mostrarei isso no MWE posterior.)
O que eu gostaria
Inspirado na resposta de @frougonaqui, eu gostaria de adotar uma abordagem completamente expl3, já que estou tentando aprender expl3 de qualquer maneira. Mas estou perdendo a cabeça e gostaria de receber ajuda. Não apenas uma solução, se você puder ser gentil, gostaria de um breve esboço para que possa estudar a solução rastreando os documentos.
MWE
\documentclass{article}
\usepackage{tabularray}
\usepackage{xcolor}
\usepackage{totcount}
% Stuff for keeping account of questions and their scores
% ........................................................<<<
\newcounter{questioncount}
\setcounter{questioncount}{0}
\regtotcounter{questioncount}%
\newcounter{scoretotal}
\setcounter{scoretotal}{0}
\regtotcounter{scoretotal}%
\newcommand{\setquestionpoints}[2]{%
\expanded{\noexpand\newtotcounter{qpoints#1}}%
\expanded{\noexpand\setcounter{qpoints#1}}{#2}%
}
\newcommand{\getquestionpoints}[1]{%
\ifnum\value{qpoints#1}>0
\arabic{qpoints#1}%
\else
0%
\fi
}
\newcommand{\TOTAL}[1]{%
\ifcsname c@#1@totc\endcsname
\total{#1}%
\else
??%
\fi
}
% ........................................................>>>
% Typesetting questions
% ........................................................<<<
\newcommand{\nquestion}[1]{%
\stepcounter{questioncount}%
\setquestionpoints{\arabic{questioncount}}{#1}%
\addtocounter{scoretotal}{#1}%
Question~\thequestioncount (#1 marks.)%
}
% ........................................................>>>
\ExplSyntaxOn
\cs_new_protected:Npn \my_typeset_table_generic:nn #1#2
{
\group_begin:
\cs_set_protected:Npn \__my_typeset_table_generic_tmp_func:n ##1 {#1}
\__my_typeset_table_generic_tmp_func:n {#2}
\group_end:
}
\cs_generate_variant:Nn \my_typeset_table_generic:nn { nV }
\ExplSyntaxOff
\begin{document}
\ExplSyntaxOn
% This works, but I would like to know how expl3 can help me build this
% list automatically, looping for
% q ∈ [1, \totvalue{questioncount}]
% to obtain \TOTAL{qpoints\theq} in each cell of the middle column.
\tl_set:Nn \l_my_tabular_tl {%
1 & \TOTAL{qpoints1} & \null \\ \hline
2 & \TOTAL{qpoints2} & \null \\ \hline
3 & \TOTAL{qpoints3} & \null \\ \hline
}
\my_typeset_table_generic:nV
{
\SetTblrInner{rowsep=1ex}%
\begin{tblr}{colspec={|ccX[c]|}, width=0.35\linewidth}
\SetRow{black, rowsep=0.25ex}
\color{white}\textit{Q}\textnumero & \color{white}Marks & \color{white}Grade \\ \hline
#1
\SetCell[c=2]{c}~TOTAL:~&~\null\\\cline[r]{3-3}
&& {\TOTAL{scoretotal}}\\\hline
\end{tblr}
}
\l_my_tabular_tl
\ExplSyntaxOff
%%% Make some questions:
\vspace{2cm}
\noindent
\nquestion{10}\\
\nquestion{12}\\
\nquestion{15}\\
\end{document}
Produz:
Responder1
O último \\
depois \nquestion{15}
causou um Badbox e foi removido.
O tblr
ambiente pode ser colocado fora do código expl3. A opção expand
no tblr
ambiente é usada. Então \my_typeset_table_generic:nn
não é mais necessário.
No tblr
ambiente, a opção rowsep=1ex
é colocada na lista de opções, as configurações da primeira linha são determinadas com a chave row{1}
. Então é desnecessário escrever \color{white}
três vezes.
A macro \null
é removida.
Os suportes ao redor \TOTAL{scoretotal}
são removidos.
No comando \nquestion
, {}
é adicionado depois \thequestioncount
para que os parênteses não sigam imediatamente após o número.
A macro \l_my_tabular_tl
não foi inicializada com \tl_new:N
. Isso agora é feito com \tl_new:N \tblrbody
.
O conteúdo é coletado com \tl_build_put_right:Nn
. Este processo é iniciado \tl_build_begin:N
e finalizado com \tl_build_end:N
.
Não é necessário colocar \setcounter{questioncount}{0}
depois \newcounter{questioncount}
porque o valor inicial já é 0.
Em vez de usar \newcounter
e \regtotcounter
, a abreviatura \newtotcounter
pode ser usada.
Não é necessário definir o comando \TOTAL
. Isso é substituído por \total
.
O comando \setquestionpoints
está integrado no comando \nquestion
. Aqui, \arabic{questioncount}
é substituído por \thequestioncount
. Para \setcounter
, \expanded
e \noexpand
são desnecessários.
Depois de \SetCell
, um &
é adicionado porque usando \SetCell
, as células omitidas não devem ser removidas.
\documentclass{article}
\usepackage{xcolor}
\usepackage{tabularray}
\usepackage{totcount}
% Stuff for keeping account of questions and their scores
% ........................................................<<<
\newtotcounter{questioncount}
\newtotcounter{scoretotal}
\newcommand{\getquestionpoints}[1]{%
\ifnum\value{qpoints#1}>0
\arabic{qpoints#1}%
\else
0%
\fi
}
% ........................................................>>>
% Typesetting questions
% ........................................................<<<
\newcommand{\nquestion}[1]{%
\stepcounter{questioncount}%
\expanded{\noexpand\newtotcounter{qpoints\thequestioncount}}%
\setcounter{qpoints\thequestioncount}{#1}%
\addtocounter{scoretotal}{#1}%
Question~\thequestioncount{} (#1 marks.)%
}
% ........................................................>>>
\begin{document}
\ExplSyntaxOn
\tl_new:N \tblrbody
\tl_build_begin:N \tblrbody
\int_step_inline:nn { \totvalue { questioncount } }
{
\tl_build_put_right:Nn \tblrbody { #1 & \total { qpoints#1 } & \\ \hline }
}
\tl_build_end:N \tblrbody
\ExplSyntaxOff
\begin{tblr}[expand=\tblrbody]{
colspec={|ccX[c]|},
width=0.35\linewidth,
rowsep=1ex,
row{1}={bg=black,fg=white,rowsep=0.25ex}
}
\emph{Q}\textnumero & Marks & Grade\\\hline
\tblrbody
\SetCell[c=2]{c} ~TOTAL:~ & & \\\cline[r]{3-3}
& & \total{scoretotal}\\\hline
\end{tblr}
%%% Make some questions:
\vspace{2cm}
\noindent
\nquestion{10}\\
\nquestion{12}\\
\nquestion{15}
\end{document}
Responder2
Encontrei uma solução onde construo as linhas de uma macro no expl3. Não acho que seja o mais elegante, mas funciona. Estou interessado em dicas/comentários para melhorá-lo, então estou deixando esta resposta sem aceitação para ver se alguém aparece com algo bonito.
\ExplSyntaxOn
\NewDocumentCommand{\ToQ}{}{
\tl_set:Nn \l_tmpa_tl {
\SetTblrInner{rowsep=1ex}%
\begin{tblr}[b]{colspec={|ccX[c]|}, width=0.35\linewidth}
\SetRow{black, rowsep=0.25ex}
\color{white}\textit{Q}\textnumero
& \color{white}Marks
& \color{white}Grade \\ \hline
}
\int_step_inline:nn {\totvalue{questioncount}} {
\tl_put_right:Nn \l_tmpa_tl { ##1 & \fromaux{qpoints##1} & \null \\ \hline }
}
\tl_put_right:Nn \l_tmpa_tl {
\SetCell[c=2]{c}~TOTAL:~&~\null\\\cline[r]{3-3}
&& {\fromaux{scoretotal}}\\\hline
\end{tblr}
}
\l_tmpa_tl
}
\ExplSyntaxOff
Produz
Responder3
A vida não precisa ser tão complicada. Sempre comece especificando como você deseja que seja a entrada e como será a saída. Isso é fornecer uma API.
- Você não precisa dos contadores LaTeX2e, use o
int
módulo. - Quando você quiser armazenar valores, pense em
csname
. - Crie uma série de comandos
\Q1
..\Qn
armazenando o valor como\Q1-marks
se quisesse, você poderia ter um\Q1-question
para armazenar a pergunta real também.
Aqui está uma solução rápida. Usei tabular, apenas para demonstrar os conceitos. Via de regra tento minimizar os pacotes que utilizo. Modifique para adicionar prefixos aos comandos l3, como é uma boa prática.
\documentclass{article}
%------------------------------------------------------------
% INPUT : \AddQuestion{name}{marks}
% OUTPUT: PrintScoreSheet
%------------------------------------------------------------
\ExplSyntaxOn
\int_new:N \g_questions_total_int
\clist_new:N \g_questions_clist
\prop_new:N \g_questions_marks_prop
\cs_new_protected:Npn \questions_add:nn #1 #2
{
\clist_gput_right:Nn \g_questions_clist {#1}
\prop_gput:Nnn \g_questions_marks_prop {#1} {#2}
}
\cs_new_protected:Npn \questions_printlist:
{
\begin{tabular}{lrr}
\hline
\clist_map_inline:Nn \g_questions_clist
{
\prop_get:NnN \g_questions_marks_prop {##1} \l_tmpa_tl
\int_gadd:Nn \g_questions_total_int { \l_tmpa_tl }
##1 & \use:c{##1-marks} &\\ %Row
}
\\\noalign{\vskip-10pt}
\cline{2-3}
Total & \int_use:N\g_questions_total_int &\\
\hline
\end{tabular}
}
\let\AddQuestion\questions_add:nn
\let\PrintScoreSheet\questions_printlist:
\ExplSyntaxOff
\begin{document}
\AddQuestion {Q1}{10}
\AddQuestion {Q2}{20}
\AddQuestion {Q3}{5}
\AddQuestion{Q4}{5}
\PrintScoreSheet
\end{document}