如果我有一个包含 5 个项目的 itemize 环境,并且我希望获得以下效果:
每次我编译时,都会以随机顺序列出 3 个随机不重复的项目。
说我的物品
- A
- 乙
- C
- 德
- 埃
经过一次编译后,输出可能如下所示:
- 德
- A
- 埃
我的问题与……密切相关,但又不同这个. 它的一个应用是从给定的一组问题中出卷。
有人知道使用乳胶是否可行吗?谢谢!
答案1
新的”LaTeX3编码界面非常适合解决此类问题。使用它,您可以使用命令拆分列表环境的内容\item
以创建序列,然后可以使用\seq_shuffle:N
命令随机打乱序列,然后允许您以随机顺序打印列表项。代码很短,一旦您熟悉了 LaTeX 3,就很容易理解。
为了实现这些想法,下面的代码定义了一个randonlist
采用可选参数的环境,该参数指定要打印的项目数——默认情况下,所有列表项都会出现,但顺序是随机的。然后,以下代码回答了 OP 中的问题:
Three random items
\begin{randomlist}[3]
\item A
\item B
\item C
\item D
\item E
\end{randomlist}
这是我第一次运行代码时生成的示例输出(每次编译文件时输出都会发生变化):
如果省略可选参数,则整个列表将被打乱:
以下是代码:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \l_randomlist_seq
\int_new:N \l_random_items_int
\NewDocumentEnvironment{randomlist}{ o +b }
{
% use a regular expression to split the environment
% around the \item commands
\regex_split:nnN { \s*\c{item}\s* } { #2 } \l_randomlist_seq
\seq_pop_left:NN \l_randomlist_seq \l_items_tl % pop empty first item
\seq_if_empty:NF \l_randomlist_seq {
\seq_shuffle:N \l_randomlist_seq %% randonly shuffle items
% the number of items to print is given by the optional #1
% defaulting to the full list of items
\IfNoValueTF{#1}{
\int_set:Nn \l_random_items_int { \seq_count:N \l_randomlist_seq}
}{
\int_set:Nn \l_random_items_int { #1 }
}
% finally, insert the itemize environment
\begin{itemize}
\int_do_while:nNnn \l_random_items_int > 0 {
\seq_pop:NN \l_randomlist_seq \l_tmpa_tl
\item \tl_use:N \l_tmpa_tl
\int_decr:N \l_random_items_int% one less item to go
}
\end{itemize}
}
}{}
\ExplSyntaxOff
\begin{document}
Five random items
\begin{randomlist}
\item A
\item B
\item C
\item D
\item E
\end{randomlist}
Three random items
\begin{randomlist}[3]
\item A
\item B
\item C
\item D
\item E
\end{randomlist}
Two random items
\begin{randomlist}[2]
\item A
\item B
\item C
\item D
\item E
\end{randomlist}
\end{document}
就我个人而言,我会enumerate
为此使用一个环境,但我已经使用了itemize
OP 中的环境。
答案2
您可以使用expl3
。通过b
参数类型,整个环境的内容都会被吸收。
我们可以将其拆分\item
(丢弃如此获得的序列中的第一个空项)。然后我们打乱序列并仅输出前三个项,或者输出可选参数中指定的数量。如果我们请求的项目多于可用项目,则没有问题。
该\seq_indexed_map_inline:Nn
函数在这方面非常方便:它生成一个整数##1
和相应的项目##2
,因此我们可以测试索引是否大于所需项目的数量或序列的长度。
这个想法是类似于 Andrew 的,但实现方式表现出不同的特点,并且更为简单。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentEnvironment{randomlist}{ O{3} +b }
{
\seq_set_split:Nnn \l__zuriel_randomlist_seq { \item } { #2 }
\seq_pop_left:NN \l__zuriel_randomlist_seq \l_tmpa_tl
\seq_shuffle:N \l__zuriel_randomlist_seq
\begin{itemize}
\seq_indexed_map_inline:Nn \l__zuriel_randomlist_seq
{
\int_compare:nTF { ##1 > \int_min:nn { #1 } { \seq_count:N \l__zuriel_randomlist_seq } }
{
\seq_map_break:
}
{
\item ##2
}
}
\end{itemize}
}{}
\seq_new:N \l__zuriel_randomlist_seq
\ExplSyntaxOff
\begin{document}
This prints three items (default)
\begin{randomlist}
\item A
\item B
\item C
\item D
\item E
\end{randomlist}
This prints two items
\begin{randomlist}[2]
\item A
\item B
\item C
\item D
\item E
\end{randomlist}
This prints five items
\begin{randomlist}[5]
\item A
\item B
\item C
\item D
\item E
\end{randomlist}
This prints five items as well
\begin{randomlist}[10]
\item A
\item B
\item C
\item D
\item E
\end{randomlist}
\end{document}