随机随机排序

随机随机排序

是否存在一个环境(或 itemize 的宏)可以在每次生成 pdf 时随机打乱所有项目?

答案1

值得一提的是,ConTeXt 开箱即用地支持此功能。只需将random键添加到即可\startitemize。(在 ConTeXt 中,\startitemize[n]相当于\begin{enumerate}LaTeX 的)。

\starttext
\startitemize[n,random]
  \startitem One \stopitem
  \startitem Two \stopitem
  \startitem Three \stopitem
  \startitem Four \stopitem
  \startitem Five \stopitem
  \startitem Six \stopitem
\stopitemize
\stoptext

这使:

在此处输入图片描述

随机种子存储在 tuc 文件中,这样每次编译文件时都会得到相同的输出(否则,多次编译会导致无限循环,并且可能无法获得所有正确的引用)。因此,您需要删除 tuc 文件来更改随机种子,从而获得不同的输出。

答案2

为了生成随机排序的列表,我定义了一个新环境,randomList,其使用方式与enumerate环境及其朋友几乎完全相同。该代码可以与enumerateitemizedescription环境一起使用,事实上,还可以与任何类似的“列表环境”一起使用,例如使用枚举项包裹。

代码\par要求每项之后都有一个空行 (a ),包括列表中的最后一项。例如,以下代码将随机排列三个列表项:

  \begin{randomList}
    \item First item

    \item Second item

    \item Third item

  \end{randomList}

列表项可以包含多行文本。段落需要用括号括起来。

基本思想是重新定义\item,以便它“吸收”从 到下\item一个 的所有内容\par,然后将其保存为名为 的宏\randomListItem@k,表示项目编号k。在“读入”列表时,1,2,...,n会构建列表索引的随机排列。最后,在环境结束时,使用\forlistloop来自电子工具箱

似乎没有一种简单/已知的方法/程序包来生成 的随机排列1,2,...,n,事实上,下面的大部分代码都用于执行此操作。随机排列是通过递归插入 的n随机排列来构建的1,2,...,n-1n插入后,它会被随机放入现有长度为 的序列中,n-1使用\pgfmathparse{random(1,n)},来自数学\randomListItem@k包。在下面的代码中,使用宏构建随机排列,同时构建项目\randomlyInsertInList。此代码可用于构建任意(逗号分隔)列表的随机排列,但我尚未对此进行测试。(另请注意,排列列表是电子工具箱列表而不是 CSV 列表。

以下是 MWE,它给出了环境所需代码的定义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}

  \textbf{Enumerate example:}

  \begin{randomList}
    \item First item

    \item Second item

    \item Third item

  \end{randomList}

  \textbf{Itemise example:}

  \begin{randomList}[itemize]
    \item First item

    \item Second item

    \item Third item

  \end{randomList}

  \textbf{Description example}

  \begin{randomList}[description]
    \item[D1] First item

    \item[D2] Second item

    \item[D3] Third item

  \end{randomList}

  \textbf{Testlist example with seed}

  \begin{randomList}[environment=Testlist, seed=4]
    \item First item

    \item Second item

    \item Third item

  \end{randomList}


\end{document}

这(目前)产生以下输出(但由于随机排序,可能会根据代码运行的时间而发生变化):

在此处输入图片描述

默认情况下,randomList随机排列环境中的项目enumerate。如 MWE 中所示,可选参数itemizedescriptionrandomList使用这两个环境(如果给出了两个或更多个环境,则最后一个获胜)。还有另一个可选参数 用于seed=<random seed>设置 使用的随机种子\pgfmathparse{random(*)}。这只需调用\pgfmathsetseed

如最后一个例子所示,该代码与枚举项\newlist包。如果使用from定义了新的列表环境,enumitemrandomList如果您使用可选参数 ,则将使用此环境environment=<listname>。(在我的实际用例中,我想使用自定义enumitem列表环境,因此这对我来说很重要。)最终,列表元素打印在枚举、逐项列出、描述... 环境中,因此适用于这些环境的任何东西都应该适用于randomList

的可选参数randomList使用以下方式处理鍵盤. 可以使用 直接访问它们\pgfkeys{/randomList, ...}

最后的评论:我认为这会很慢,但我基本上使用这个代码来生成 20 个问题列表的三个随机排序版本,以及一些其他内容,而且它真的很快!

答案3

今天(对于楼主来说已经很晚了)我发现randomlist包,其中包括提供\RandomItemizeList\RandomEnumerateList命令。这些命令会产生它们所说的内容,即带有或不带有编号的项目的随机列表。

举个小例子:

\documentclass{article}
\usepackage{randomlist}
\begin{document}
This is a random list of items:
\RandomItemizeList{First item}{Second item}{Third item}{Fourth item}
and this is an enumerated random list of items: 
\RandomEnumerateList{First item}{Second item}{Third item}{Fourth item}
\end{document}

第一次编译后,它产生:

在此处输入图片描述

第二次编译得到:

在此处输入图片描述

等等。

答案4

由于的通常实现\begin{list} \item ... \item ... \item ... \end{list}不会读取或保存项目的实际文本,如果您想要相同的界面,则需要进行一些超出我能力范围的黑客攻击来保存然后排列列表项。

我问了一个类似问题在几年前的 pgf-users 邮件列表中。这是 Mark Wibrow 对随机化 PGF 列表(声明为 )的回答\pgfmathdeclarelist。从那时起,我就把这个片段放到了我的考试文件中。

\documentclass{article} 
\usepackage{tikz} 

\begin{document} 

\makeatletter 
\def\pgfmathdeclarelist#1#2{% 
        \def\pgfmath@list@name{#1}% 
        \c@pgfmath@counta=0% 
        \pgfmath@declarelistlist#2{\pgfmath@stop}% 
}% 
\def\pgfmath@declarelistlist#1{% 
        \ifx#1\pgfmath@stop% 
                \expandafter\edef\csname pgfmath@list@\pgfmath@list@name 
@length\endcsname{\the\c@pgfmath@counta}% 
        \else% 
                \advance\c@pgfmath@counta by1\relax% 
                \pgfutil@namedef{pgfmath@list@\pgfmath@list@name @\the\c@pgfmath@counta}{#1}% 
                \expandafter\pgfmath@declarelistlist% 
        \fi% 
} 

\def\pgfmathgetlistitem#1#2#3{\expandafter\let\expandafter#1\expandafter=\csname 
pgfmath@list@#2@#3\endcsname} 

\def\pgfmathsetlistitem#1#2#3{% 
        \pgfutil@namedef{pgfmath@list@#1@#2}{#3}% 
} 

\def\pgfmathgetlistlength#1#2{% 
        \expandafter\let\expandafter#1\expandafter=\csname 
pgfmath@list@#2@length\endcsname% 
} 

\def\pgfmathknuthshuffle#1{% 
        \pgfmathgetlistlength\pgfmath@len{#1}% 
        \pgfmathloop% 
        \ifnum\pgfmathcounter>\pgfmath@len% 
        \else% 
                \pgfmathrandominteger\pgfmath@temp{1}{\pgfmath@len}% 
                \pgfmathgetlistitem\pgfmath@@temp{#1}{\pgfmathcounter}% 
                \pgfmathgetlistitem\pgfmath@@@temp{#1}{\pgfmath@temp}% 
                \def\pgfmath@marshal{\pgfmathsetlistitem{#1}}% 
                \expandafter\pgfmath@marshal\expandafter{\expandafter\pgfmath@temp\expandafter}\expandafter{\pgfmath@@temp}% 
                \expandafter\pgfmath@marshal\expandafter{\expandafter\pgfmathcounter\expandafter}\expandafter{\pgfmath@@@temp}% 
        \repeatpgfmathloop% 
} 

\makeatother 

\pgfmathdeclarelist{mylist}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}{M}} 
\pgfmathgetlistlength{\l}{mylist} 

\begin{tikzpicture}[every node/.style={circle, draw}] 

\foreach \i in {1,...,\l}{ 
        \pgfmathgetlistitem{\x}{mylist}{\i} 
        \node at (0,-\i) (\x-1) {\x}; 
} 

\pgfmathknuthshuffle{mylist} 

\foreach \i in {1,...,\l}{ 
        \pgfmathgetlistitem{\x}{mylist}{\i} 
        \node at (7.5,-\i) (\x-2) {\x}; 
} 

\foreach \i in {1,...,\l}{ 
        \pgfmathgetlistitem{\x}{mylist}{\i} 
        \draw [->] (\x-1) -- (\x-2); 
} 

\end{tikzpicture} 
\end{document} 

相关内容