我使用本教程中的 prune list 命令生成无重复的随机数以避免在生成随机序列时出现重复。但是,如果我尝试在框架框中使用此命令,它不起作用。在minipage
环境中也是如此。为什么会发生这种情况?
\documentclass[a4paper,14pt]{extreport}
\usepackage{tikz}
\newcommand\lengthof[1]{\csname pgfmath@randomlist@#1\endcsname}
\newcommand\nthof[2]{\csname pgfmath@randomlist@#2@#1\endcsname}
\def\mylist{{one}{two}{three}{four}{five}}
\pgfmathdeclarerandomlist{mynum}{\mylist} %Define the list
\makeatletter
\def\prunelist#1{% Define prunelist command
\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}
\makeatother
\newcommand\prnrnd{%
\pgfmathrandomitem{\mynum}{mynum}\mynum %get and print item from list
\prunelist{mynum} %prune list by selected item}
\begin{document}
\foreach \i in {1, ..., \lengthof{mynum}}%show list
{\par\textit{\nthof{\i}{mynum}}}\\
\fbox{\prnrnd}%extract item (item wasn't extracted!)
\foreach \i in {1, ..., \lengthof{mynum}}%show list
{\par\textit{\nthof{\i}{mynum}}}\\
\prnrnd%extract item
\foreach \i in {1, ..., \lengthof{mynum}}%show list
{\par\textit{\nthof{\i}{mynum}}}\\
\prnrnd%extract item
\foreach \i in {1, ..., \lengthof{mynum}}%show list
{\par\textit{\nthof{\i}{mynum}}}\\
\end{document}
答案1
您甚至不需要 来\fbox
显示此效果;\prnrnd
用括号括起来就足够了。解释是 的更改\prunelist
仅限于当前组。在组之外(\fbox
也形成一个组),您将返回到旧值, 的效果\prnrnd
已被撤消。
这里有两种解决方案;我推荐第一个。
改变框外的列表
我建议修改您的\prnrnd
命令,使其不打印元素,而只是将其存储在宏中。然后您可以在框外执行它并使用框内存储的元素。\prnrnd
用以下定义替换。
\newcommand\nextrnd[2]%
{\pgfmathrandomitem{\tmp}{#2}% select random element
\edef#1{\tmp}% store random element in #1
\prunelist{#2}%prune list by selected item
}
\nextrnd{<var>}{<list>}
将从中挑选并移除下一个随机元素<list>
并将其存储在中<var>
。
为了使您的代码更易于阅读,我还定义了一个用于列出列表内容的宏。
\newcommand\showrndlist[1]%
{\foreach \i in {1, ..., \lengthof{#1}}
{\par\textit{\nthof{\i}{#1}}}%
\bigskip
}
这是完整的代码及其输出。
\documentclass{article}
\usepackage{pgffor}
\newcommand\lengthof[1]{\csname pgfmath@randomlist@#1\endcsname}
\newcommand\nthof[2]{\csname pgfmath@randomlist@#2@#1\endcsname}
\newcommand\nextrnd[2]%
{\pgfmathrandomitem{\tmp}{#2}% select random element
\edef#1{\tmp}% store random element in #1
\prunelist{#2}%prune list by selected item
}
\newcommand\showrndlist[1]%
{\foreach \i in {1, ..., \lengthof{#1}}
{\par\textit{\nthof{\i}{#1}}}%
\bigskip
}
\makeatletter
\def\prunelist#1{% Define prunelist command
\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}
\makeatother
\begin{document}
\def\mylist{{one}{two}{three}{four}{five}}
\pgfmathdeclarerandomlist{mynum}{\mylist}% Define the list
\showrndlist{mynum}
\nextrnd\rnd{mynum}% Store random element in \rnd and remove it from mynum
\fbox{\rnd}% The random element can be put inside a box
\showrndlist{mynum}
\nextrnd\rnd{mynum}% Store random element in \rnd and remove it from mynum
{\rnd}% ... or inside a group
\showrndlist{mynum}
\nextrnd\rnd{mynum}% Store random element in \rnd and remove it from mynum
\rnd
\showrndlist{mynum}
\end{document}
\prunelist
使全球影响
您可以通过替换来使永久效果\prunelist
超出组范围
\expandafter\edef
经过
\expandafter\xdef
和
\expandafter\let
经过
\expandafter\global\expandafter\let
这样定义就变成了
\makeatletter
\def\prunelist#1{% Define prunelist command
\expandafter\xdef\csname pgfmath@randomlist@#1\endcsname % <<< \edef changed to \xdef
{\the\numexpr\csname pgfmath@randomlist@#1\endcsname-1\relax}
\count@\pgfmath@randomtemp
\loop
\expandafter\global\expandafter\let % <<< \expandafter\global added
\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}
\makeatother