生成无重复的随机数

生成无重复的随机数

如何在 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}

随机III

答案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

相关内容