自动更改目录条目的顺序

自动更改目录条目的顺序

我本质上想要实现相同的目标问题。但是,与该帖子中的解决方案不同,我无法手动执行此操作,它需要自动执行

我定义了一个\problemand\solution命令,其工作原理如下例所示。添加一个带有问题引用的新解决方案将匹配数字,一切顺利。使用tocloft,我还设法生成了 TOC 样式的“问题列表”。

\documentclass[12pt]{article}
\usepackage{tocloft}
\usepackage{hyperref}
\hypersetup{
  colorlinks=true,
  linkcolor=black
}
\usepackage{tcolorbox}
\usepackage[parfill]{parskip}

\definecolor{darkgreen}{RGB}{0, 180, 0}

% Create the "List of Problems" object
\newlistof{problems}{prob}{List of Problems}
% Create the look of the problem and solution boxes
\newtcbox{\problembox}{on line,
                    colframe=red,
                    colback=red!20,
                    boxrule=1pt,
                    arc=4pt,
                    boxsep=0pt,
                    left=2pt,
                    right=2pt,
                    top=2pt,
                    bottom=2pt}
\newtcbox{\solutionbox}{on line,
                    colframe=darkgreen,
                    colback=darkgreen!20,
                    boxrule=1pt,
                    arc=4pt,
                    boxsep=0pt,
                    left=2pt,
                    right=2pt,
                    top=2pt,
                    bottom=2pt}
% Create the counter that keeps track of the problem number
\newcounter{problemnb}
% Create the main \problem and \solution commands. These will:
% 1. Print out the problem/solution boxes with the correct number (kept track of by the "problemnb" counter)
% 2. Add a line to the "List of Problems" (with the name given in the optional argument)
% Problems and solutions are linked by the \label-\ref pairs (as with figures e.g.)
% \problem[problem name (optional)]{problem reference}
\newcommand{\problem}[2][Problem \theproblemnb]{%        
    \newcounter{problem#2counter}
    \refstepcounter{problemnb}%
    \problembox{\color{red}\textbf{PROBLEM \theproblemnb}\label{#2}}
    \addcontentsline{prob}{section}{#1}
}
% \solution[solution name (optional)]{problem reference} (solution name defaults to "Solution" without number)
\newcommand{\solution}[2][Solution]{{%
    \hypersetup{linkcolor=darkgreen}
    \stepcounter{problem#2counter}
    \solutionbox{\color{darkgreen}\textbf{SOLUTION \ref{#2}.\the\value{problem#2counter}}}
    \addcontentsline{prob}{subsection}{#1}}
}
    
\begin{document}
\listofproblems

\problem[First problem]{prob:first} This is the first problem encountered. \\
\solution[Solution to first problem]{prob:first} I fixed it somehow. \\
\solution[Another solution to first problem]{prob:first} Found an even better fix. \\
\\
\problem[Another problem]{prob:another} Oh dear, another problem has arisen. \\
\solution[Good solution to second problem]{prob:another} This is a great fix for it, though. \\
% All good up to now
\solution[Solution to the first problem]{prob:first} This is a solution to the first problem, but it will appear in the LoP as a solution to the second.
\end{document}

代码的输出。

现在的问题是,任何放在后续\problem命令之后的先前问题的解决方案都将放在 LoP 中的新问题之下。这显然是不可取的。

我认为有两种可能的解决方案:

  1. 使用已经到位的\label系统\ref以某种方式告诉 LoP 将哪些小节放在哪些节下。
  2. 从一开始就浏览整个文档,列出所有问题及其相应的解决方案,然后“手动”创建整个 LoP(当然使用宏),并将各节和小节放在正确的位置。

现在的问题是,我没有足够的知识/技能来实现其中任何一个。我已经找到了手动创建目录的方法(如策略 2 所要求的),但我必须找到一种方法,在文档的最开始就列出章节和小节的列表。

任何帮助是极大的赞赏。

附言:我并不坚持使用tocloft,它只是迄今为止我想要做的最简单的方法。

答案1

以下是使用 Expl3 属性列表和序列来跟踪数据的方法。我们创建问题标签和标题的属性列表,以及相应的键序列来跟踪它们的顺序。

每当创建一个新问题时,它都会根据问题标签创建一个新序列,并且该序列将保存该问题的每个解决方案的标题。

最后,我们创建一个在文档末尾运行的命令,将所有问题和解决方案添加到问题列表中。

\documentclass[12pt]{article}
\usepackage{tocloft}
\usepackage{hyperref}
\hypersetup{
  colorlinks=true,
  linkcolor=black
}
\usepackage{tcolorbox}
\usepackage[parfill]{parskip}

\definecolor{darkgreen}{RGB}{0, 180, 0}
\ExplSyntaxOn
% Property list of problem labels (key) and titles (value)
\prop_new:N \l_PeterPawn_problems_prop
% Since property lists aren’t ordered, we also keep track of the keys in order using a sequence
\seq_new:N \l_PeterPawn_problems_seq
% Add a warning for duplicate keys
\msg_new:nnnn {PeterPawn}{key-exists}{\\This\ problem\ is\ already\ defined!}{Help\ text\ here.}
% command to add a solution for a particular problem
\NewDocumentCommand{\addsolution}{mm}{
    \seq_gput_right:cn {l_PeterPawn_#1_solutions_seq} {#2}
    }
% command to add a problem to the problem property list and sequence
\NewDocumentCommand{\addproblem}{mm}{
    {\prop_get:NnNTF \l_PeterPawn_problems_prop {#1} \l_tmpa_tl
    {\msg_warning:nn { PeterPawn } { key-exists }}
    {\prop_gput:Nnn \l_PeterPawn_problems_prop {#1} {#2}
     \seq_gput_right:Nn \l_PeterPawn_problems_seq {#1}
    }}}
    
% Create the main \problem and \solution commands. These will:
% 1. Print out the problem/solution boxes with the correct number (kept track of by the "problemnb" counter)
% 2. Add a line to the "List of Problems" (with the name given in the optional argument)
% Problems and solutions are linked by the \label-\ref pairs (as with figures e.g.)
% \problem[problem name (optional)]{problem reference}
% Modified to use the \addproblem and \addsolution code
\NewDocumentCommand{\problem}{O{Problem \theproblemnb}m}{%        
    \newcounter{problem#2counter}
    \seq_new:c {l_PeterPawn_#2_solutions_seq}
    \refstepcounter{problemnb}%
    \problembox{\color{red}\textbf{PROBLEM\ \theproblemnb}\label{#2}}
    \addproblem{#2}{#1} 
}
\NewDocumentCommand{\solution}{O{Solution}m}{{%
    \hypersetup{linkcolor=darkgreen}
    \stepcounter{problem#2counter}
    \solutionbox{\color{darkgreen}\textbf{SOLUTION\ \ref{#2}.\the\value{problem#2counter}}}
    \addsolution{#2}{#1}
}}

% This command must appear at the end of the document text!
\NewDocumentCommand{\makeprobscontents}{}{
    \seq_map_function:NN \l_PeterPawn_problems_seq \PeterPawn_addcontents:n}

% function to map problems and solutions to the list of problems    
\cs_new_protected:Nn \PeterPawn_addcontents:n {
        \tl_set:Nn \l_tmpa_tl {#1}
        \prop_get:NnN \l_PeterPawn_problems_prop {#1} \l_tmpb_tl
         \addcontentsline{prob}{section}{\l_tmpb_tl}
        \seq_map_function:cN {l_PeterPawn_#1_solutions_seq} \PeterPawn_addsolutions:n
}
% function to map solutions to the list of problems
\cs_new_protected:Nn \PeterPawn_addsolutions:n {
    \tl_set:Nn \l_tmpa_tl {#1}
    \addcontentsline{prob}{subsection}{\l_tmpa_tl}
}
\ExplSyntaxOff

% Create the "List of Problems" object
\newlistof{problems}{prob}{List of Problems}
% Create the look of the problem and solution boxes
\newtcbox{\problembox}{on line,
                    colframe=red,
                    colback=red!20,
                    boxrule=1pt,
                    arc=4pt,
                    boxsep=0pt,
                    left=2pt,
                    right=2pt,
                    top=2pt,
                    bottom=2pt}
\newtcbox{\solutionbox}{on line,
                    colframe=darkgreen,
                    colback=darkgreen!20,
                    boxrule=1pt,
                    arc=4pt,
                    boxsep=0pt,
                    left=2pt,
                    right=2pt,
                    top=2pt,
                    bottom=2pt}
% Create the counter that keeps track of the problem number
\newcounter{problemnb}
    
\begin{document}

\listofproblems

\problem[First problem]{prob:first} This is the first problem encountered. \\
\solution[Solution to first problem]{prob:first} I fixed it somehow. \\
\solution[Another solution to first problem]{prob:first} Found an even better fix. \\
\\
\problem[Another problem]{prob:another} Oh dear, another problem has arisen. \\
\solution[Good solution to second problem]{prob:another} This is a great fix for it, though. \\
% All good up to now
\solution[Solution to the first problem]{prob:first} This is a solution to the first problem, and it will appear correctly now in the LoP as a solution to the the first problem as desired!.

% Need to issue this command at the end of the document
\makeprobscontents
\end{document}

代码输出

相关内容