我从以下代码获得随机随机排序。
如何标记(类似 \label{1}, \ref{1})特定的 randomList 项以在文档末尾打印相应的字母?
\documentclass{article}
\usepackage{etoolbox}
\usepackage{pgfkeys}
\usepackage{pgfmath}
% code for generating a random permutation
\newcounter{randomListLength}% current length of our random list
\newcounter{randomListPosition}% current list index
\newcounter{newRandomListElementPosition}% position to insert new element
% insert #1 into the next position of \newRandomList unless the position
% index \randomListPosition is equal to \newRandomListElementPosition in
% which case the \newRandomListElement is added first
\newcommand\randomlyInsertElement[1]{%
\stepcounter{randomListPosition}%
\ifnum\value{randomListPosition}=\value{newRandomListElementPosition}%
\listxadd\newRandomList{\newRandomListElement}%
\fi%
\listxadd\newRandomList{#1}%
}
% \randomlyInsertInList{list name}{new list length}{new element}
\newcommand\randomlyInsertInList[3]{%
\pgfmathparse{random(1,#2)}%
\setcounter{newRandomListElementPosition}{\pgfmathresult}%
\ifnum\value{newRandomListElementPosition}=#2\relax%
\listcsxadd{#1}{#3}%
\else%
\def\newRandomList{}% start with an empty list
\def\newRandomListElement{#3}% and the element that we need to add
\setcounter{randomListPosition}{0}% starting from position 0
\xdef\currentList{\csuse{#1}}
\forlistloop\randomlyInsertElement\currentList%
\csxdef{#1}{\newRandomList}%
\fi%
}
% define some pgfkeys to allow key-value arguments
\pgfkeys{/randomList/.is family, /randomList,
environment/.code = {\global\letcs\beginRandomListEnvironment{#1}
\global\letcs\endRandomListEnvironment{end#1}
},
enumerate/.style = {environment=enumerate},
itemize/.style = {environment=itemize},
description/.style = {environment=description},
seed/.code = {\pgfmathsetseed{#1}}
}
\pgfkeys{/randomList, enumerate}% enumerate is the default
% finally, the code to construct the randomly permuted list
\makeatletter
\newcounter{randomListCounter}% for constructing \randomListItem@<k>'s
% \useRandomItem{k} prints item number k
\newcommand\useRandomItem[1]{\csname randomListItem@#1\endcsname}
% \setRandomItem{k} saves item number k for future use
% and builds a random permutation at the same time
\def\setRandomItem#1\par{\stepcounter{randomListCounter}%
\expandafter\protected@xdef\csname randomListItem@\therandomListCounter\endcsname{\noexpand\item#1}%
\randomlyInsertInList{randomlyOrderedList}{\therandomListCounter}{\therandomListCounter}%
}%
\let\realitem=\item
\makeatother
\newenvironment{randomList}[1][]{% optional argument -> pgfkeys
\pgfkeys{/randomList, #1}% process optional arguments
\setcounter{randomListLength}{0}% initialise length of random list
\def\randomlyOrderedList{}% initialise the random list of items
% Nthing is printed in the main environment. Instead, \item is
% used to slurp the "contents" of the item into randomListItem@<counter>
\let\item\setRandomItem%
}
{% now construct the list environment by looping over the randomly ordered list
\let\item\realitem
\setcounter{randomListCounter}{0}
\beginRandomListEnvironment\relax
\forlistloop\useRandomItem\randomlyOrderedList
\endRandomListEnvironment
}
% test compatibility with enumitem
\usepackage{enumitem}
\newlist{Testlist}{enumerate}{1} %
\setlist[Testlist]{label*=\alph*.}
\setlist{nosep}\parindent=0pt% for more compact output
\begin{document}
\begin{randomList}[environment=Testlist, seed=4]
\item First item
\item Second item
\item Third item
\end{randomList}
\end{document}
答案1
必须使用固定种子,否则参考将会从一次运行变为另一次运行。
\documentclass{article}
\usepackage{xparse,environ,enumitem}
\ExplSyntaxOn
\NewEnviron{randomList}[1][]
{
\keys_set:nn { lucas/randomlist } { #1 }
\seq_set_split:NnV \l__lucas_randomlist_items_seq { \item } \BODY
% discard the empty first item
\seq_pop_left:NN \l__lucas_randomlist_items_seq \l_tmpa_tl
\seq_shuffle:N \l__lucas_randomlist_items_seq
\begin{\l__lucas_randomlist_env_tl}
\item \seq_use:Nn \l__lucas_randomlist_items_seq { \item }
\end{\l__lucas_randomlist_env_tl}
}
\cs_generate_variant:Nn \seq_set_split:Nnn { NnV }
\keys_define:nn { lucas/randomlist }
{
environment .tl_set:N = \l__lucas_randomlist_env_tl,
seed .code:n = \sys_gset_rand_seed:n { #1 },
}
\ExplSyntaxOff
\newlist{Testlist}{enumerate}{1} %
\setlist[Testlist]{label*=\alph*.}
\setlist{nosep}\parindent=0pt% for more compact output
\begin{document}
\begin{randomList}[environment=Testlist, seed=4]
\item\label{1} First item
\item Second item
\item Third item
\end{randomList}
\ref{1}
\end{document}
您还可以制作答案,只要它晚于练习即可。
\documentclass{article}
\usepackage{xparse,environ,enumitem}
\ExplSyntaxOn
\NewEnviron{randomList}[1][]
{
\keys_set:nn { lucas/randomlist } { #1 }
\lucas_randomlist:V \BODY
}
\NewDocumentCommand{\answerkey}{}
{
\subsubsection*{Answer ~ key}
\begin{enumerate}[nosep]
\seq_map_inline:Nn \g_lucas_randomlist_answers_seq { \item ##1 }
\end{enumerate}
}
\NewDocumentCommand{\correct}{}
{
\seq_gput_right:Nx \g_lucas_randomlist_answers_seq { \use:c { @currentlabel } }
}
\keys_define:nn { lucas/randomlist }
{
environment .tl_set:N = \l__lucas_randomlist_env_tl,
seed .code:n = \sys_gset_rand_seed:n { #1 },
}
\seq_new:N \g_lucas_randomlist_answers_seq
\cs_new_protected:Nn \lucas_randomlist:n
{
\seq_set_split:Nnn \l__lucas_randomlist_items_seq { \item } { #1 }
% discard the empty first item
\seq_pop_left:NN \l__lucas_randomlist_items_seq \l_tmpa_tl
\seq_shuffle:N \l__lucas_randomlist_items_seq
\begin{\l__lucas_randomlist_env_tl}
\item \seq_use:Nn \l__lucas_randomlist_items_seq { \item }
\end{\l__lucas_randomlist_env_tl}
}
\cs_generate_variant:Nn \lucas_randomlist:n { V }
\ExplSyntaxOff
\newlist{Testlist}{enumerate}{1}
\setlist[Testlist]{label*=\alph*.}
\setlist{nosep}\parindent=0pt% for more compact output
\begin{document}
\begin{enumerate} % outer list of exercises
\item First exercise
\begin{randomList}[environment=Testlist]
\item\correct First item
\item Second item
\item Third item
\end{randomList}
\item Second exercise
\begin{randomList}[environment=Testlist]
\item First item
\item\correct Second item
\item Third item
\end{randomList}
\item Third exercise
\begin{randomList}[environment=Testlist]
\item\correct First item
\item Second item
\item Third item
\end{randomList}
\end{enumerate}
\answerkey
\end{document}