如何在 LaTeX 中生成给定范围内的随机整数列表,避免重复?该命令\pgfmathrandomitem
从列表中选择一个项目,但插入循环时可以选择两次相同的项目。由于我从列表中选择问题是为了准备考试,所以我不能问两次相同的问题。
答案1
您可以在选择项目后将其从列表中删除,这样它就不会再次被选中:
\documentclass{article}
\usepackage{tikz}
\begin{document}
\makeatletter
\pgfmathsetseed{123321}
\def\prunelist#1{%
\expandafter\edef\csname pgfmath@randomlist@#1\endcsname
{\the\numexpr\csname pgfmath@randomlist@#1\endcsname-1\relax}
\count@\pgfmath@randomtemp
\loop
\expandafter\let
\csname pgfmath@randomlist@#1@\the\count@\expandafter\endcsname
\csname pgfmath@randomlist@#1@\the\numexpr\count@+1\relax\endcsname
\ifnum\count@<\csname pgfmath@randomlist@#1\endcsname\relax
\advance\count@\@ne
\repeat}
\pgfmathdeclarerandomlist{mylist}{{one}{two}{three}{four}{five}{six}{seven}}
\pgfmathrandomitem\z{mylist}\z\prunelist{mylist}
\pgfmathrandomitem\z{mylist}\z\prunelist{mylist}
\pgfmathrandomitem\z{mylist}\z\prunelist{mylist}
\pgfmathrandomitem\z{mylist}\z\prunelist{mylist}
\pgfmathrandomitem\z{mylist}\z\prunelist{mylist}
\pgfmathrandomitem\z{mylist}\z\prunelist{mylist}
\pgfmathrandomitem\z{mylist}\z\prunelist{mylist}
\end{document}
声明一个整数列表:
\def\declarenumlist#1#2#3{%
\expandafter\edef\csname pgfmath@randomlist@#1\endcsname{#3}%
\count@\@ne
\loop
\expandafter\edef
\csname pgfmath@randomlist@#1@\the\count@\endcsname
{\the\count@}
\ifnum\count@<#3\relax
\advance\count@\@ne
\repeat}
%\pgfmathdeclarerandomlist{mylist}{{one}{two}{three}{four}{five}{six}{seven}}
\declarenumlist{mylist}{1}{10}% list from 1 to 10 inclusive.
答案2
1
此代码用于生成从到 的无重复随机数,其N
运行速度应比基于 的代码快pgfmath
。这里感觉不到速度提升,因为数字是逐个提取的,但如果想要一次性生成一个完整的随机排列以供以后使用,则可以扩展此代码来执行此操作,并且pgfmath+\prune
在处理N
几百个以上数字时应该会显示与 的差异。(未经测试;-)
)。
编辑:添加代码,一次性生成来自 的整数的完全随机排列1..N
。与此相反\NewRandom
,每次将列表“修剪”一个,\NewPermutation
保持列表完整,以便允许迭代使用。
最后编辑:\DeclareList
作为 的配套添加\DeclareIntegerList
,但现在用于任意事物的列表。重命名\NewPermutation
为\Permutation
并重写代码,不再重复使用\NewRandom
及其附带开销。
\documentclass{article}
\usepackage[vscale=0.9,hscale=0.75]{geometry}
% \DeclareIntegerList {name}{N}
% declares the list of the integers from 1 to N
% under name "name" for future use of either
% \NewRandom<macro>\FromList {name},
% or \Permutation<macro>\OfList{name}
% \DeclareList {name}{{first}{second}...{last}}
% declares similarly a list of things, possibly containing empty lines or
% `\par`. Second argument may be macro. Items must be braced (or single tokens
% but the first one will be expanded if not protected by braces)
% \NewRandom\z \FromList {name}
% makes \z expand to a randomly chosen element in what remains of list
% "name", and removes the chosen element from the list "name"
% \Permutation\R \OfList {name}
% makes \R expand to the token list of the braced elements of list
% "name", in a random order. The list is not modified.
\makeatletter
\newtoks\rndperm@tok
\newcount\rndperm@cnta
\newcount\rndperm@cntb
% auxiliary macros \rndperm@tmpa, \rndperm@tmpb, \rndperm@aux
\newcommand{\DeclareIntegerList}[2]{%
% sets up a the integers from 1 to N as a list for random extraction
\rndperm@cnta #2\relax
\rndperm@cntb \rndperm@cnta
\rndperm@tok {}%
\loop
\rndperm@tok
\expandafter\expandafter\expandafter{%
\expandafter\the\expandafter\rndperm@tok
\csname \the\rndperm@cntb\expandafter\endcsname
\expandafter{\the\rndperm@cntb}}%
\ifnum\rndperm@cntb>\@ne
\advance\rndperm@cntb\m@ne
\repeat
\expandafter\def\csname rndperm@list@#1\expandafter\endcsname
\expandafter{\the\rndperm@tok }%
\expandafter\def\csname rndperm@card@#1\expandafter\endcsname
\expandafter{\the\rndperm@cnta }%
}%
\newcommand{\NumberOfItems}[1]{\csname rndperm@card@#1\endcsname }
\newcommand{\DeclareList}[2]{%
\rndperm@cnta \z@
\rndperm@tok {}%
\expandafter\rndperm@scanlist \romannumeral-`0#2\rndperm@bye
\long\expandafter\def\csname rndperm@list@#1\expandafter\endcsname
\expandafter{\the\rndperm@tok }%
\expandafter\def\csname rndperm@card@#1\expandafter\endcsname
\expandafter{\the\rndperm@cnta }%
}%
\long\def\rndperm@bye #1\rndperm@bye {}%
\def\rndperm@endscan #1\rndperm@scanlist {}%
\long\def\rndperm@scanlist #1{%
\rndperm@bye #1\rndperm@endscan\rndperm@bye
\advance\rndperm@cnta\@ne
\long\expandafter\def\expandafter\rndperm@tmpa\expandafter
{\csname\the\rndperm@cnta\endcsname {#1}}%
\rndperm@tok\expandafter\expandafter\expandafter
{\expandafter\rndperm@tmpa\the\rndperm@tok }%
\rndperm@scanlist
}%
\def\NewRandom #1\FromList #2{%
\rndperm@cnta \csname rndperm@card@#2\endcsname\relax
\ifnum\rndperm@cnta=\z@\rndperm@abort #1\fi
\expandafter\let\expandafter\rndperm@list\csname rndperm@list@#2\endcsname
\rndperm@cntb\pdfuniformdeviate\rndperm@cnta\relax
\advance\rndperm@cnta\m@ne
\ifnum\rndperm@cntb=\rndperm@cnta
\expandafter\rndperm@firstone
\else
\expandafter\rndperm@fartherup
\fi
\expandafter\def\csname rndperm@card@#2\expandafter\endcsname
\expandafter{\the\rndperm@cnta}%
\long\expandafter\def\expandafter#1\expandafter{\rndperm@element}%
\expandafter\let\csname rndperm@list@#2\endcsname\rndperm@list
\empty
}%
\def\rndperm@abort #1\fi #2\empty{\fi \let#1\empty}
\def\rndperm@firstone {\expandafter\rndperm@firstone@a \rndperm@list!}%
\long\def\rndperm@firstone@a #1#2#3!{%
\long\def\rndperm@element {#2}%
\long\def\rndperm@list {#3}}
\def\rndperm@fartherup {%
\expandafter\def\expandafter\rndperm@tmpa
\expandafter{\csname\the\numexpr\rndperm@cntb+1\endcsname }%
\rndperm@tok {\long\def\rndperm@aux ##1##2##3}%
\expandafter\the\expandafter\rndperm@tok\rndperm@tmpa ##4##5!%
{\long\expandafter\def
\expandafter\rndperm@tmpa\expandafter{\rndperm@tmpa {##2}##5}%
\long\def\rndperm@tmpb {##3}%
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\rndperm@list
\expandafter\expandafter\expandafter
{\expandafter\rndperm@tmpb\rndperm@tmpa }%
\long\def\rndperm@element {##4}}%
\expandafter\rndperm@aux \rndperm@list!%
}%
\def\Permutation #1\OfList #2{%
\rndperm@cnta \csname rndperm@card@#2\endcsname\relax
\let\rndperm@perm\empty
\ifnum\rndperm@cnta>\z@
\expandafter\expandafter\expandafter
\rndperm@all\csname rndperm@list@#2\endcsname
\fi
\let#1\rndperm@perm
}%
\def\rndperm@all {%
\rndperm@cntb\pdfuniformdeviate\rndperm@cnta\relax
\advance\rndperm@cnta\m@ne
\ifnum\rndperm@cntb=\rndperm@cnta
\expandafter\rndperm@all@firstone
\else
\expandafter\rndperm@all@fartherup
\fi
}%
\long\def\rndperm@all@firstone #1#2{%
\long\expandafter\def\expandafter\rndperm@perm\expandafter
{\rndperm@perm {#2}}%
\ifnum\rndperm@cnta>\z@ \expandafter\rndperm@all\fi
}%
\def\rndperm@all@fartherup {%
\expandafter\def\expandafter\rndperm@tmpa
\expandafter{\csname\the\numexpr\rndperm@cntb+1\endcsname }%
\rndperm@tok {\long\def\rndperm@aux ##1##2##3}%
\expandafter\the\expandafter\rndperm@tok\rndperm@tmpa ##4%
{\long\expandafter\def\expandafter\rndperm@perm\expandafter
{\rndperm@perm {##4}}%
\long\expandafter\def\expandafter\rndperm@tmpa
\expandafter{\rndperm@tmpa {##2}}%
\long\def\rndperm@tmpb {##3}%
\expandafter\expandafter\expandafter\rndperm@all
\expandafter\rndperm@tmpb\rndperm@tmpa
}%
\rndperm@aux
}%
\makeatother
\begin{document}
\begin{verbatim}
\DeclareIntegerList {mylist}{10}
\count 255 1
\loop
\NewRandom\z\FromList {mylist}\z
\ifnum\count 255 < 15 \advance\count 255 by 1 ,
\repeat
\end{verbatim}
\DeclareIntegerList {mylist}{10}
\count 255 1
\loop
\NewRandom\z\FromList {mylist}\z
\ifnum\count 255 < 15 \advance\count 255 by 1 ,
\repeat (macro is set to empty when the list is exhausted)
\begin{verbatim}
\DeclareList {words}{{Unpounced}{epimetheus}{angelhood}{diopside}% (percent optional)
{gospeler}{quiff}{eutrophy}}
\count 255 1
{\bfseries\loop
\NewRandom\z\FromList {words}\z
\ifnum\count 255 < 7 \advance\count 255 by 1 ,
\repeat }
\end{verbatim}
\DeclareList {words}{{Unpounced}{epimetheus}{angelhood}{diopside}%
{gospeler}{quiff}{eutrophy}}
\count 255 1
{\bfseries\loop
\NewRandom\z\FromList {words}\z
\ifnum\count 255 < 7 \advance\count 255 by 1 ,
\repeat }
At this stage \texttt{words} has no more elements, it is emptied.
% \verb|\Permutation\S\OfList {mylist}| sets \texttt{\string\S} to the empty macro
% (meaning of \texttt{\string\S} is \Permutation\S\OfList
% {mylist}\texttt{\meaning\S}).
\begin{verbatim}
\def\x #1{\ifx \relax #1\else \{#1\}\hskip 0pt plus 1pt minus 1pt
\expandafter\x \fi }
\DeclareList {words}{{Unpounced}{epimetheus}{angelhood}{diopside}%
{gospeler}{quiff}{eutrophy}}
\Permutation\S\OfList {words}\texttt{\string\S\ is \expandafter\x\S\relax}\endgraf
\end{verbatim}
\def\x #1{\ifx \relax #1\else \{#1\}\hskip 0pt plus 1pt minus 1pt
\expandafter\x \fi }
\DeclareList {words}{{Unpounced}{epimetheus}{angelhood}{diopside}%
{gospeler}{quiff}{eutrophy}}
\noindent
\Permutation\S\OfList {words}\texttt{\string\S\ is \expandafter\x\S\relax}\endgraf
\noindent\Permutation\S\OfList {words}\texttt{\string\S\ is \expandafter\x\S\relax}\endgraf
\noindent\Permutation\S\OfList {words}\texttt{\string\S\ is \expandafter\x\S\relax}\endgraf
\noindent\Permutation\S\OfList {words}\texttt{\string\S\ is \expandafter\x\S\relax}\endgraf
\medskip
We can declare lists of arbitrary contents
\begin{verbatim}
\DeclareList {tokens}{{\if}{{\ifnum}}{\ifdim}{\par}{\end}{\fi}{{\fi\fi}}{\gobbleall}}%
There are \NumberOfItems {tokens} elements in this list.\endgraf
\noindent\Permutation\S\OfList {tokens}\noindent\texttt{\meaning\S}\endgraf
\noindent\Permutation\S\OfList {tokens}\noindent\texttt{\meaning\S}\endgraf
\noindent\Permutation\S\OfList {tokens}\noindent\texttt{\meaning\S}\endgraf
\noindent\Permutation\S\OfList {tokens}\noindent\texttt{\meaning\S}\endgraf
\end{verbatim}
\DeclareList {tokens}{{\if}{{\ifnum}}{\ifdim}{\par}{\end}{\fi}{{\fi\fi}}{\gobbleall}}
There are \NumberOfItems {tokens} elements in this list.\endgraf
\noindent\Permutation\S\OfList {tokens}\texttt{\meaning\S}\endgraf
\noindent\Permutation\S\OfList {tokens}\texttt{\meaning\S}\endgraf
\noindent\Permutation\S\OfList {tokens}\texttt{\meaning\S}\endgraf
\noindent\Permutation\S\OfList {tokens}\texttt{\meaning\S}\endgraf
\begin{verbatim}
\DeclareIntegerList {mylist}{200}
\texttt{mylist} has \NumberOfItems {mylist} elements and a random element is
\NewRandom\z \FromList {mylist}\texttt{\z}. There are now only \NumberOfItems
{mylist} elements left. Here they are in random order:
\Permutation\S\OfList {mylist}%
\texttt{\expandafter\x\S\relax}
\end{verbatim}
\DeclareIntegerList {mylist}{200}
\texttt{mylist} has \NumberOfItems {mylist} elements and a random element is
\NewRandom\z \FromList {mylist}\texttt{\z}. There are now only \NumberOfItems
{mylist} elements left. Here they are in random order:
\Permutation\S\OfList {mylist}%
\texttt{\expandafter\x\S\relax}
\end{document}
\medskip
Extracting 200 times with no repetitions
after \verb|\DeclareIntegerList {mylist}{200}|:
\DeclareIntegerList {mylist}{200}\count 255 1
\begin{verbatim}
\count255 0
\loop
\NewRandom\z\FromList {mylist}\z
\ifnum\count 255 < 200 \advance\count 255 1 ,
\repeat
\end{verbatim}
\count255 0
\loop
\NewRandom\z\FromList {mylist}\z
\ifnum\count 255 < 200
\advance\count 255 1
,
\repeat
\medskip
Now with
\begin{verbatim}
\DeclareIntegerList {mylist}{200}
\Permutation\S\OfList {mylist}
\end{verbatim}
\DeclareIntegerList {mylist}{200}
\Permutation\S\OfList {mylist}
Here are the contents of \texttt{\string\S}:
\def\x #1{\ifx \relax #1\else \{#1\}\hskip 0pt plus 1pt minus 1pt
\expandafter\x \fi }
\texttt{\expandafter\x\S\relax}
And \verb|\Permutation| can be used again and again to generate more random
permutations (not necessarily distinct).
% Tools of \verb|xint| such as \verb|\xintApplyUnbraced| or \verb|\xintFor*| can
% help if one wants to do things with the generated list of braced things.
\end{document}
答案3
前段时间我们在网上发现了这段代码:
\input random
\newcount\icount
\newcount\i
\newcount\j
% Define a new item.
\def\defitem{%
\advance\icount by1
% Define a macro with the name `n' where n is the item's number.
\expandafter\def \csname \number\icount \endcsname
}
% Printing of items.
\def\printitem#1{\csname \number#1\endcsname}
\let\printbetweenitems\space
% Print all defined items in random order.
\def\getitems{%
% Unset all flags.
\i=\icount
\loop
\expandafter\let \csname flag\number\i \endcsname a%
\advance\i by-1
\ifnum\i > 0 \repeat
% Print random items, each item once, until every item has been
% printed.
\i=\icount
\loop
% Get random number \j.
\setrannum{\j}{1}{\icount}%
% Print item \j only if its flag is unset.
\expandafter\ifx \csname flag\number\j \endcsname a%
\expandafter\let \csname flag\number\j \endcsname b% Set the flag.
\printitem\j
\advance\i by-1
\ifnum\i > 0 \printbetweenitems\fi
\fi
\ifnum\i > 0 \repeat
}
\defitem{1}
\defitem{2}
\defitem{3}
\defitem{4}
\defitem{5}
\defitem{6}
\defitem{7}
\defitem{8}
\defitem{9}
\defitem{10}
\defitem{11}
\getitems\par \getitems\par \getitems\par \getitems\par
\getitems\par
\bye
我们对其进行了调整,以创建一个命令,该命令从 n 个对象(m <= n)中随机选择 m 个对象。
您可以通过此链接查看 esami.sty 文件 https://www.dropbox.com/sh/0t92kehukgafni5/0Mi0qsYLlR