Expl3 для упрощения задач расширения с содержимым Tabularray, построенным в цикле

Expl3 для упрощения задач расширения с содержимым Tabularray, построенным в цикле

Продолжение отмой предыдущий вопросответил спасибо @egreg. (Возможно, профессор Грегорио тоже сможет мне помочь.)

Ситуация

Я создаю макрос Table of Questions (ToQ) для создания таблицы оценок на обложке экзамена или задания. Он работал нормально, tabularно я переключился на Tabularray tblr, в который я влюбился. К сожалению, поскольку я использую totcountдля создания счетчиков оценок в каждом новом вопросе по мере их появления, я сталкиваюсь с проблемами расширения, которые поставили меня сегодня в тупик.

Проблема

Циклы не могут быть помещены внутрь tblrсреды (см.§3.2.3руководства), как и в случае с обычными табличными. Но решения, которые, похоже, работают для обычных табличных:

  • с использованием примитивных циклов LaTeX,
  • построение тела вне таблицы как \gdef, сделанного из \edefs, и
  • создание тела как регистра токенов,

не работали для tblr. Кроме того, tblrпозволяет указать expandопцию указания токенов для расширения до того, как он обработает тело. (Я покажу это в более позднем MWE.)

Что бы я хотел

Вдохновлено ответом @frougonздесь, я хотел бы использовать полностью expl3 подход, так как я пытаюсь изучить expl3 в любом случае. Но я запутался и был бы признателен за помощь. Не просто решение, если вы могли бы быть так любезны, я хотел бы получить краткий план, чтобы я мог изучить решение, просматривая документы.

МВЭ

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

Производит:

решение1

Последнее последующее \\вызвало \nquestion{15}Badbox, поэтому оно удалено.

Окружение можно вынести за пределы кода expl3. Используется tblrопция expandв окружении. Тогда больше не нужна.tblr\my_typeset_table_generic:nn

В tblrсреде опция rowsep=1exпомещается в список опций, настройки для первой строки определяются ключом row{1}. Тогда нет необходимости писать \color{white}три раза.

Макрос \nullудален.

Брекеты вокруг \TOTAL{scoretotal}сняты.

В команде после добавляется \nquestion, чтобы скобки не следовали сразу за числом.{}\thequestioncount

Макрос \l_my_tabular_tlне был инициализирован с помощью \tl_new:N. Теперь это делается с помощью \tl_new:N \tblrbody.

Содержимое собирается с помощью \tl_build_put_right:Nn. Этот процесс начинается с \tl_build_begin:Nи заканчивается с помощью \tl_build_end:N.

Ставить \setcounter{questioncount}{0}после не нужно \newcounter{questioncount}, так как начальное значение уже равно 0.

Вместо использования \newcounterand можно использовать \regtotcounterсокращение .\newtotcounter

Нет необходимости определять команду \TOTAL. Она заменяется на \total.

Команда \setquestionpointsинтегрирована в команду \nquestion. Здесь \arabic{questioncount}заменяется на \thequestioncount. Для \setcounter, \expandedи \noexpandне нужны.

После добавляется \SetCell, поскольку при использовании пропущенные ячейки не должны удаляться.&\SetCell

введите описание изображения здесь

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

решение2

Я нашел решение, в котором я строю строки макроса в expl3. Я не думаю, что это самое элегантное, но это работает. Мне интересны советы/комментарии по его улучшению, поэтому я оставляю этот ответ непринятым, чтобы посмотреть, добавит ли кто-нибудь что-нибудь красивое.

\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

Производит

введите описание изображения здесь

решение3

Жизнь не обязательно должна быть такой сложной. Всегда начинайте с указания того, как вы хотите, чтобы были входные данные и каковы выходные данные. То есть предоставьте API.

  1. Вам не нужны счетчики LaTeX2e, используйте модуль int.
  2. Если вы хотите сохранить значения, подумайте о csname.
  3. Создайте ряд команд \Q1, \Qnсохраняющих значение, как \Q1-marksесли бы вы хотели, вы могли бы \Q1-questionтакже сохранить фактический вопрос.

Вот быстрое решение. Я использовал табличный формат, просто чтобы продемонстрировать концепции. Как правило, я стараюсь минимизировать пакеты, которые использую. Пожалуйста, измените, чтобы добавить префиксы к командам l3, как это принято.

выход

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

Связанный контент