1

Feel free to skip past this explanation to the code below. My issue is trying to get \Q@Selection to work with edef.

I have a macro that uses a for loop to assign some dynamic macros that I am toying with to figure out how some things work. The goal was to take a bunch of macros that were generated using a for loop, then shuffle them, and then build a set of macros that have them shuffled.

I have a command \Knuth@Shuffle{Max#}{Name}{Pick#} Which generates (pick#) of counters, named NameI, NameII, ..., Name\Roman{Pick#}, each of which containing a random (non repeating) number 1 - Max#.

Using that, I then want to assign a new set of macros by selecting the pick# of macros from a pre-generated list of macros of the form Question@\Roman{(number)} for numbers 1 to Max#. But I want to pick the random ones, so I am using: Question@\Roman{Name\Roman{(number)}} to pull the random choice. Since I need to assign these values inside a loop, I need to use \edef to make sure that the values are assigned as the loop runs and not at the end (effectively giving me the same macro a bunch of times)

Code:

Function that fails:

\newcommand{\Q@Selection}{%     The Command that Selects and stores Qs
\setcounter{Iteration@Select}{1}
%
\Knuth@Shuffle{\arabic{Problem@MasterCounter}}{Q@Pulled}{\arabic{Real@PullNumber}}%             Start For Loop
\forloop{Iteration@Select}{1}{\arabic{Iteration@Select} < \arabic{Real@PullNumber}}%    Iterate for each desired question
    {%                                  Start Iteration Step
    \expandafter\edef\csname Q@\Roman{Iteration@Select}\endcsname{\csname Question@\Roman{Q@Pulled\Roman{Iteration@Select}}\endcsname}% Select the question that was the "Q@Pull" number from the start. Currently capable of pulling the same question twice.
    }%                                  End Iteration Step
%                                   End for Loop
}

Supporting code if you want to see how the randomize function works:

\newcommand{\@genrand}[3] %\@genrand{NAME}{MIN}{MAX} generates a random number before MIN and MAX and stores it in the command \NAME.
{
\expandafter\pgfmathrandominteger\csname #1\endcsname{#2}{#3}
\setcounter{#1}{\csname #1\endcsname}
}

\newcommand{\Knuth@Shuffle}[3]% \Knuth@Shuffle{MAXCOUNT}{NAME}{USEDCOUNT} Generates and permutes a list MAXCOUNT number of counters, each with name NAMEI, NAMEII, NAMEIII, ..., NAME\Roman(MAXCOUNT). Then it stores up to USEDCOUNT of those counters in counters named 
{
%Assign a maximum on how many numbers to pick. Set default to the max list size, and save in counter "RndQuant"
\ifthenelse{\isempty{#3}}%          Check to see if Desired Maximum is given.
    {
    \setcounter{Rnd@Quant}{#1+1}        %If not, use all of them.
    }
    {
    \ifthenelse{#1 < #3}
        {
        \setcounter{Rnd@Quant}{#1+1}        %Only select up to all problems.
        }
        {
        \setcounter{Rnd@Quant}{#3+1}        
        }
    }

\setcounter{Rnd@EndQuant}{#1+1}

%Generate a starting list of numbers 1 to maximum number given.
\forloop{Iteration@1}{1}{\arabic{Iteration@1} < \arabic{Rnd@EndQuant}}
    {
    \@ifundefined{c@#2\Roman{Iteration@1}}  % Check to see if counter exists
        {                                   %If not, make it.
        \newcounter{#2\Roman{Iteration@1}}
        }
        {}                                  %If so, do nothing.
    \setcounter{#2\Roman{Iteration@1}}{\arabic{Iteration@1}}    % Set Counter to next number.
    }

%Permute using Knuth method
\forloop{Iteration@2}{1}{\arabic{Iteration@2} < \arabic{Rnd@Quant}}
    {
    \@genrand{Temp@RandMe}{\arabic{Iteration@2}}{#1}%   Generate a random number from Current iterate number to maximum number.

    \setcounter{Temp@Hold}{\arabic{#2\Roman{Temp@RandMe}}}% Set a temp variable so that we can swap values in position of the iterate and the random number selected. 

    \setcounter{#2\Roman{Temp@RandMe}}{\arabic{#2\Roman{Iteration@2}}}% Set the final counter to the value of the variable in the generated number's counter.
    \setcounter{#2\Roman{Iteration@2}}{\arabic{Temp@Hold}}% Set current counter to the swapped counter.
}
}

As a footnote: I was writing this largely to learn how to do some things but if anyone has suggestions of a much cleaner and nicer way to do this I'd appreciate the advice as well. I like learning on my own but that doesn't mean I'll ignore good advice.

  • You're trying to do too much here at once. My suggestion would be to find the main source of your problem - the \edef, and only focus on that as the problem. Then, provide a simplified - yet comprehensive - version of it without nesting it inside a for loop. – Werner Dec 10 '16 at 6:30
  • As Werner says, please post a minimal working example. Ideally, this should be code that is as small as possible so as to illustrate your problem. That is, modulo your \edef-issue, your code should compile. Of course, in cutting down your code to a MWE you may well find what the real problem is yourself:) – user30471 Dec 10 '16 at 7:23
  • The usual advice here is using \protected@edef instead of \edef – egreg Dec 10 '16 at 10:26
  • I actually determined a vastly better way to do what I want that shouldn't need \edef in the first place so I don't need this resolved. That being said I would like to understand what fails. For what it's worth, if you just replace \edef with \def in the code above it compiles fine (but not with the info I want), but I can't for the life of me figure out what is going wrong to know what the minimal level is. Without the for loop everything appears to work as well (in fact, the error listed is 'for loop used incorrectly' among others). – Jason Dec 10 '16 at 16:14
4

The TeX engine as provided by Knuth does have only 256 count registers.
Therefore avoid permanently reserving count registers whenever possible.

\expandafter\pgfmathrandominteger\csname #1\endcsname{#2}{#3} does imply an assignment while \edef does expansion only which means that assignments within the definition text of an \edef do not get carried out at definition time. Instead the corresponding tokens are left in place and they become part of the definition text of the macro that is about to be defined by \edef. This means these tokens get 'spit out' whenever the macro defined by \edef gets carried out/expanded.

If I got you right, you wish to call in random order in time a particular number of different macros whose names can be derived from numbers in a certain range of integers. No macro shall be called twice.

An issue with LaTeX is that often more than one compilation is required until everything matches out as mechanisms like \tableofcontents, \label..\ref, hyperlinks, ..., rely on information gathered during the previous LaTeX compilation.

If random numbers are used for creating portions of text randomly, each LaTeX compilation might deliver another text with other pagebreaks while \tableofcontents, \label..\ref, hyperlinks etc rely on information gathered during the previous LaTeX compilation.
If you don't do anything about it, this might end up in a never ending story as information gathered during the previous LaTeX compilation never corresponds to page-numbering etc within the current LaTeX compilation.

Therefore having a mechanism that stores a random value in the .aux-file and makes it available similar to the \label..\ref- mechanism appears to be be a good idea.

Due to answers being limited to 30000 characters I decided to post coding examples in other answers:

Example 1 can be found at: https://tex.stackexchange.com/a/344282/118714
Example 2 can be found at: https://tex.stackexchange.com/a/344287/118714

| improve this answer | |
  • This is exactly the kind of info I was looking for, thanks! – Jason Dec 12 '16 at 17:54
  • Are you aware that duration of compilation is unpredictable with my current approach of randomly getting a permutation of k unequal elements from a set of (k+l) elements? An approach where compilation-time is predictable would be to associate each of these permutations with a number in a way where numbers are consecutive and each number is associated to exactly one permutation and then choose randomly one of these numbers... – Ulrich Diez Dec 12 '16 at 18:55
  • I'm not a mathematician but an approach could be: If you wish to randomly call K different macros of N different macros whose names can be derived from numbers in range 0..(N-1), then choose randomly a number in range 0..(N!-1), calculate its N digits in factorial-number-system representation (with leading zeroes if needed), take these N digits for the Lehmer Code of a permutation of N Elements, decode that Lehmer Code in order to obtain the associated permutation of N Elements and keep only the first K elements of that permutation as the sequence of numbers from which to derive K macro names. – Ulrich Diez Dec 13 '16 at 0:54
  • I actually realized that my pool is huge, but the number I'm calling is (relatively) tiny. So I redesigned the system entirely. Currently as the first version before I try to optimize anything, I input the list of questions, each contained in a command that iterates a counter. After the input I pull the counter to get how many questions, randomly pick x numbers between 1 and max, then reset the counter and go through the input again. When the counter matches one of the random numbers, then I record that in the "next" dummy macro. So I only have x macros at the end. Seems to work for now... – Jason Dec 13 '16 at 5:22
  • I suspect there's a nicer way of doing this with only reading through the list once, or perhaps a more efficient way to check each problem to see if it's one I want. Normally I'd just remove the problem number from the list of desirable problems once I found it in the list, but I'm not sure how to do that in latex and still have the loops work nicely. I haven't tried much yet, but was thinking about trying something with a counter to track how many desirable questions remained. For reference, I'm scanning about 50,000-60,000 questions looking for 20-30 tops. – Jason Dec 13 '16 at 14:06
0

Coding example 1 to answer https://tex.stackexchange.com/a/343436/118714

Does the following code do what you want?

\documentclass{article}
\usepackage{pgf}
%
\makeatletter
%
\newcommand\exchange[2]{#2#1}%
\newcommand\firstoftwo[2]{#1}%
\newcommand\secondoftwo[2]{#2}%
%
\newcommand\Name{}\long\def\Name#1#{\Innername{#1}}%
\newcommand\Innername[2]{%
  \expandafter\exchange\expandafter{\csname#2\endcsname}{#1}%
}%
%
\newcommand\innerdfork{}\def\innerdfork#1d#2#3dd{#2}%
\newcommand*\dfork[1]{\innerdfork#1{\firstoftwo}d{\secondoftwo}dd}%
%
%%......................................................................
%% \RetrieveRandomfromlabel{<name of label>}%
%%                         {<macro>}%
%%                         {<lower bound>}%
%%                         {<upper bound>}%
%%                         {<amount>}%
%%                         {<action in case label is undefined or changed>}%
\newcommand\RetrieveRandomfromlabel[6]{%
  \@ifundefined{@random@#1}{\firstoftwo}{%
    \ifnum\Name
          \expandafter\expandafter
          \expandafter\firstoftwo
          \expandafter\secondoftwo{@random@#1}=#3 %
    \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
    {%
      \ifnum\Name
            \expandafter\expandafter\expandafter\expandafter
            \expandafter\expandafter\expandafter\firstoftwo
            \expandafter\expandafter\expandafter\secondoftwo
            \expandafter\secondoftwo{@random@#1}=#4 %
      \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
      {%
        \ifnum\Name
              \expandafter\expandafter\expandafter\expandafter
              \expandafter\expandafter\expandafter\secondoftwo
              \expandafter\expandafter\expandafter\secondoftwo
              \expandafter\secondoftwo{@random@#1}=#5 %
        \expandafter\secondoftwo\else\expandafter\firstoftwo\fi
      }{\firstoftwo}%
    }%
    {\firstoftwo}%
  }%
  {#6}%
  {%
    \expandafter\expandafter\expandafter\expandafter
    \expandafter\expandafter\expandafter\newcommand
    \expandafter\expandafter\expandafter\expandafter
    \expandafter\expandafter\expandafter#2%
    \expandafter\expandafter\expandafter\expandafter
    \expandafter\expandafter\expandafter{%
    \expandafter\expandafter\expandafter\firstoftwo
    \csname @random@#1\endcsname}%
  }%
}%
\newcommand\newrandomlabel{\@newl@bel{@random}}%
%% \WriteRandomMacrotolabel{<macro>}%
%%                         {<label>}%
%%                         {<lower bound>}%
%%                         {<upper bound>}%
%%                         {<amount>}%
\newcommand\WriteRandomtolabel[5]{%
  \protected@write\@auxout{}{\string\newrandomlabel{#2}{{#1}{{#3}{{#4}{#5}}}}}%
}%
%
\newcommand\createlistofdifferentrandomintegers[5]{%
  \ifnum#2<1 \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {%
    \@latex@error{Lower bound is not a positive number}%
                 {Lower bound must a positive number.}%
  }{%
    \ifnum#2>#3 \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
    {\@latex@error{Lower bound greater than upper bound}%
                  {Lower bound must not be greater than upper bound.}%
    }{%
      \begingroup
      \@tempcnta=#3\relax
      \advance\@tempcnta by 1%
      \advance\@tempcnta -#2\relax
      \expandafter\endgroup
      \expandafter\ifnum\the\@tempcnta<#1 %
        \expandafter\@firstoftwo
      \else
        \expandafter\@secondoftwo
      \fi
      {\@latex@error{Amount of elements to randomize on is
                     smaller than amount of elements to create}%
                    {Finding more unequal numbers than there are numbers
                     contained in the set from which numbers are to be
                     chosen randomly is not possible. See Dirichlet's
                     drawer principle.}%
      }{%
        \RetrieveRandomfromlabel{#4}{#5}{#2}{#3}{#1}{%
          \expandafter\exchange
          \expandafter{%
          \romannumeral\number\number#1 000d}{%
            \innercreatelistofdifferentrandomintegers{}{#2}{#3}{#5}%
          }%
        }%
        \WriteRandomtolabel{#5}{#4}{#2}{#3}{#1}%
      }%
    }%
  }%
}%
%
\newcommand\innercreatelistofdifferentrandomintegers[5]{%
  \dfork{#5}{\newcommand#4{#1}}{%
    \CreateRandomNumbersUntilNumberIsNotInList{#1}{#2}{#3}{#4}%
  }%
}%
%
\newcommand\mytempa{}%
\newcommand\CreateRandomNumbersUntilNumberIsNotInList[3]{%
  \pgfmathrandominteger\mytempa{#2}{#3}%
  \CheckIfNumMyTempaIsAlreadyInList#1{}{}\relax
  {%
    \CreateRandomNumbersUntilNumberIsNotInList{#1}{#2}{#3}%
  }{%
    \expandafter\innercreatelistofdifferentrandomintegers
    \expandafter{%
    \expandafter{%
    \mytempa}#1}{#2}{#3}%
  }%
}%
\newcommand\CheckIfNumMyTempaIsAlreadyInList{}%
\long\def\CheckIfNumMyTempaIsAlreadyInList#1#2\relax{%
  \ifx\relax#1\relax
    \expandafter\firstoftwo
  \else
    \expandafter\secondoftwo
  \fi
  {\secondoftwo}{%
     \ifnum\mytempa=#1 %
       \expandafter\firstoftwo
     \else
       \expandafter\secondoftwo
     \fi
     {\firstoftwo}%
     {\CheckIfNumMyTempaIsAlreadyInList#2\relax}%
  }%
}%
%
%
\newcommand\DoWithEachElementOfIntegerlist[2]{%
  \expandafter\exchange
  \expandafter{%
  #1}{\InnerDoWithEachElementOfIntegerlist{#2}}\relax
}%
\newcommand\InnerDoWithEachElementOfIntegerlist[2]{%
  \ifx\relax#2%
    \expandafter\firstoftwo
  \else
    \expandafter\secondoftwo
  \fi
  {}%
  {#1{#2}\InnerDoWithEachElementOfIntegerlist{#1}}%
}%
%
%
\newcommand\CallMacroNumber[1]{%
  \Name\string{Macro#1}:~%
  \Name{\@ifundefined{Macro#1}{Undefined}{Macro#1}}%
}%
\makeatother

\begin{document}

%Define twenty macros whose names contain the prefix "Macro" and arabic digits:
\Name\newcommand{Undefined}{!!Undefined!!\\}
\Name\newcommand{Macro1}{Number One\\}
\Name\newcommand{Macro2}{Number Two\\}
\Name\newcommand{Macro3}{Number Three\\}
\Name\newcommand{Macro4}{Number Four\\}
\Name\newcommand{Macro5}{Number Five\\}
\Name\newcommand{Macro6}{Number Six\\}
\Name\newcommand{Macro7}{Number Seven\\}
\Name\newcommand{Macro8}{Number Eight\\}
\Name\newcommand{Macro9}{Number Nine\\}
\Name\newcommand{Macro10}{Number Ten\\}
\Name\newcommand{Macro11}{Number Eleven\\}
\Name\newcommand{Macro12}{Number Twelve\\}
\Name\newcommand{Macro13}{Number Thirteen\\}
\Name\newcommand{Macro14}{Number Fourteen\\}
\Name\newcommand{Macro15}{Number Fifteen\\}
\Name\newcommand{Macro16}{Number Sixteen\\}
\Name\newcommand{Macro17}{Number Seventeen\\}
\Name\newcommand{Macro18}{Number Eighteen\\}
\Name\newcommand{Macro19}{Number Nineteen\\}
\Name\newcommand{Macro20}{Number Twenty\\}


% This creates a list of eleven different random numbers in range of 1..20
% and stores that list in the macro \ListOfRandomNumbers:
% In consecutive LaTeX-runs when aux-file exists, number-list will not
% created anew but be taken from randomize-label "LABEL"
\createlistofdifferentrandomintegers{11}{1}{20}{LABEL}{\ListOfRandomNumbers}%

\ttfamily

\noindent
\string\ListOfRandomNumbers: \meaning\ListOfRandomNumbers
\bigskip

\noindent
% This calles the Macros according to the number list stored in \ListOfRandomNumbers:
\DoWithEachElementOfIntegerlist{\ListOfRandomNumbers}{\CallMacroNumber}

\end{document}

enter image description here

| improve this answer | |
0

Coding example 2 to answer https://tex.stackexchange.com/a/343436/118714

You might wish to be able to call each macro separately:

\documentclass{article}
\usepackage{pgf}
%
\makeatletter
\newcommand\exchange[2]{#2#1}%
\newcommand\firstoftwo[2]{#1}%
\newcommand\secondoftwo[2]{#2}%
%%-------------------------------------------------------------------------
%% \Name<emptiness or tokens that are not nested in braces>{<NameOfControlSequence>}
%% yields:
%% <emptiness or tokens that are not nested in braces>\NameOfControlSequence
%%-------------------------------------------------------------------------
\newcommand\Name{}\long\def\Name#1#{\romannumeral\Innername{#1}}%
\newcommand\Innername[2]{%
  \expandafter\exchange\expandafter{\csname#2\endcsname}{0 #1}%
}%
%%======================================================================
%% Write a label expanding to a random number to the aux-file.
%% (In case the label is defined from the previous LaTeX compilation
%%  and the values for <lower bound for randomize> and <upper bound for
%%  randomize> did not change, take the value from the label stored in
%%  the .aux-file. Otherwise create a new value by means of
%%  \pgfrandominteger. In any case write that value and <lower bound for
%%  randomize> and <upper bound for randomize> to the .aux file so you
%%  can check whether something did change between the previous and the
%%  current LaTeX compilation.)
%%......................................................................
%% \RetrieveRandomfromlabel{<name of label>}%
%%                         {<macro>}%
%%                         {<lower bound>}%
%%                         {<upper bound>}%
%%                         {<amount>}%
%%                         {<action in case label is undefined or changed>}%
\newcommand\RetrieveRandomfromlabel[6]{%
  \@ifundefined{@random@#1}{\firstoftwo}{%
    \ifnum\Name
          \expandafter\expandafter
          \expandafter\firstoftwo
          \expandafter\secondoftwo{@random@#1}=#3 %
    \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
    {%
      \ifnum\Name
            \expandafter\expandafter\expandafter\expandafter
            \expandafter\expandafter\expandafter\firstoftwo
            \expandafter\expandafter\expandafter\secondoftwo
            \expandafter\secondoftwo{@random@#1}=#4 %
      \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
      {%
        \ifnum\Name
              \expandafter\expandafter\expandafter\expandafter
              \expandafter\expandafter\expandafter\secondoftwo
              \expandafter\expandafter\expandafter\secondoftwo
              \expandafter\secondoftwo{@random@#1}=#5 %
        \expandafter\secondoftwo\else\expandafter\firstoftwo\fi
      }{\firstoftwo}%
    }%
    {\firstoftwo}%
  }%
  {#6}%
  {%
    \expandafter\expandafter\expandafter\expandafter
    \expandafter\expandafter\expandafter\newcommand
    \expandafter\expandafter\expandafter\expandafter
    \expandafter\expandafter\expandafter#2%
    \expandafter\expandafter\expandafter\expandafter
    \expandafter\expandafter\expandafter{%
    \expandafter\expandafter\expandafter\firstoftwo
    \csname @random@#1\endcsname}%
  }%
}%
\newcommand\newrandomlabel{\@newl@bel{@random}}%
%%----------------------------------------------------------------------
%% Define a macro to expand to the value stored in a "random-label".
%%......................................................................
%% \WriteRandomMacrotolabel{<macro>}%
%%                         {<label>}%
%%                         {<lower bound>}%
%%                         {<upper bound>}%
%%                         {<amount>}%
\newcommand\WriteRandomtolabel[5]{%
  \protected@write\@auxout{}{\string\newrandomlabel{#2}{{#1}{{#3}{{#4}{#5}}}}}%
}%
%%-------------------------------------------------------------------------
%% \CreateMappingToDifferentRandomIntegers{<amount of random numbers>}%
%%                                     {<lower randomize range>}%
%%                                     {<upper randomize range>}%
%%                                     {<label prefix>}%
%%                                     {<prefix of names of mapping macros>}
\newcommand\CreateMappingToDifferentRandomIntegers[5]{%
  \@bsphack
  \ifnum#2<1 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
  {%
    \@latex@error{Lower bound is not a positive number}%
                 {Lower bound must a positive number.}%
  }{%
    \ifnum#2>#3 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
    {\@latex@error{Lower bound greater than upper bound}%
                  {Lower bound must not be greater than upper bound.}%
    }{%
      \begingroup
      \@tempcnta=#3\relax
      \advance\@tempcnta by 1%
      \advance\@tempcnta -#2\relax
      \expandafter\endgroup
      \expandafter\ifnum\the\@tempcnta<#1 %
        \expandafter\firstoftwo
      \else
        \expandafter\secondoftwo
      \fi
      {\@latex@error{Amount of elements to randomize on is
                     smaller than amount of elements to create}%
                    {Finding more unequal numbers than there are numbers
                     contained in the set from which numbers are to be
                     chosen randomly is not possible. See Dirichlet's
                     drawer principle.}%
      }{%
        \ErrorCheckingDoneCreateMappingToDifferentRandomIntegers{1}{}{}{#1}{#2}{#3}{#4}{#5}%
      }%
    }%
  }%
  \@esphack
}%
%% \ErrorCheckingDoneCreateMappingToDifferentRandomIntegers
%%   {<number K of K-th random-mapping element that is to be defined>}%
%%   {<List of random numbers>}%
%%   {<List of assignments>}% <- When this list gets carried out, random-mapping elements will get defined: \newcommand\<prefix of names of mapping macros><K>{<random number>}
%%   {<Amount of random-mapping elements that are to be defined>}%
%%   {<lower randomize range>}%
%%   {<upper randomize range>}%
%%   {<label prefix>}%
%%   {<prefix of names of mapping macros>}
%%
%%  Checks if there are already
%%  <Amount of random-mapping elements that are to be defined>
%%  assignments collected in the <List of assignments>.
%%  If so: Spit out the <List of assignments> for having them carried out.
%%  If not: Create a random number.
\newcommand\ErrorCheckingDoneCreateMappingToDifferentRandomIntegers[8]{%
  \ifnum#1>#4 %
    \expandafter\firstoftwo
  \else
    \expandafter\secondoftwo
  \fi
  {%
    #3%
    \Name\newcommand{#8}[1]{%
      \@ifundefined{#8##1}{MappingUNDefIneD}{\Name{#8##1}}%
    }%
  }{%
    \begingroup
    \CreateRandomNumbersUntilNumberIsNotInList{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}%
  }%
}%
%% \CreateRandomNumbersUntilNumberIsNotInList
%%    Repeat creating a random number until a number is found which
%%    is not already in the <List of Random Numbers>.
%%    Then
%%    - add that number to the <List of random numbers>
%%    - add an assignment-directive to the <List of assignments>
%%    - increment K
%%    - call \ErrorCheckingDoneCreateMappingToDifferentRandomIntegers.
%%
\newcommand\CreateRandomNumbersUntilNumberIsNotInList[8]{%
  \RetrieveRandomfromlabel{#7#1}{\mytempa}{#5}{#6}{#4}{%
    \pgfmathrandominteger\mytempa{#5}{#6}%
  }%
  \CheckIfNumMyTempaIsAlreadyInList#2{}{}\relax
  {%
    \CreateRandomNumbersUntilNumberIsNotInList{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}%
  }{%
     % WriteLabel #7#1 {{Wert}{{obere grenze}{{untere grenze}{menge}}}}
    \WriteRandomtolabel{\mytempa}{#7#1}{#5}{#6}{#4}%
    \@tempcnta=#1\relax
    \advance\@tempcnta 1\relax
    \expandafter\callErrorCheckingDoneCreateMappingToDifferentRandomIntegers
    \expandafter{%
    \number\expandafter\@tempcnta
           \expandafter}%
           \expandafter{%
           \mytempa}{#2}{#8#1}{#3}%
    {#4}{#5}{#6}{#7}{#8}%
  }%
}%
\newcommand\CheckIfNumMyTempaIsAlreadyInList{}%
\long\def\CheckIfNumMyTempaIsAlreadyInList#1#2\relax{%
  \ifx\relax#1\relax
    \expandafter\firstoftwo
  \else
    \expandafter\secondoftwo
  \fi
  {\secondoftwo}{%
     \ifnum\mytempa=#1 %
       \expandafter\firstoftwo
     \else
       \expandafter\secondoftwo
     \fi
     {\firstoftwo}%
     {\CheckIfNumMyTempaIsAlreadyInList#2\relax}%
  }%
}%
%
\newcommand\callErrorCheckingDoneCreateMappingToDifferentRandomIntegers[5]{%
  \endgroup
  \ErrorCheckingDoneCreateMappingToDifferentRandomIntegers{#1}%
                                              {{#2}#3}%
                                              {\Name\newcommand{#4}{#2}#5}%
}%
%
%
%
\newcommand\CallFamilysMacro[2]{%
  \Name{#1\@ifundefined{#1#2}{UNDefIneD}{#2}}%
}%
%
%
%
\newcommand\DefineInstanceOfMacroFamily[2]{%
  \Name\newcommand{#1#2}%
}%
\makeatother

\begin{document}

% Define a family of macros consisting of 20 elements plus the macros
% that are to be executed
%  - in case it is attempted to call a "family member" which is undefined
%  - in case it is attempted to map to a family member from a number where no mapping is defined.
\DefineInstanceOfMacroFamily{Macro}{UNDefIneD}{!!Macro undefined!!\\}
\DefineInstanceOfMacroFamily{Macro}{MappingUNDefIneD}{!!No Mapping defined!!\\}
\DefineInstanceOfMacroFamily{Macro}{1}{Number One\\}
\DefineInstanceOfMacroFamily{Macro}{2}{Number Two\\}
\DefineInstanceOfMacroFamily{Macro}{3}{Number Three\\}
\DefineInstanceOfMacroFamily{Macro}{4}{Number Four\\}
\DefineInstanceOfMacroFamily{Macro}{5}{Number Five\\}
\DefineInstanceOfMacroFamily{Macro}{6}{Number Six\\}
\DefineInstanceOfMacroFamily{Macro}{7}{Number Seven\\}
\DefineInstanceOfMacroFamily{Macro}{8}{Number Eight\\}
\DefineInstanceOfMacroFamily{Macro}{9}{Number Nine\\}
\DefineInstanceOfMacroFamily{Macro}{10}{Number Ten\\}
\DefineInstanceOfMacroFamily{Macro}{11}{Number Eleven\\}
\DefineInstanceOfMacroFamily{Macro}{12}{Number Twelve\\}
\DefineInstanceOfMacroFamily{Macro}{13}{Number Thirteen\\}
\DefineInstanceOfMacroFamily{Macro}{14}{Number Fourteen\\}
\DefineInstanceOfMacroFamily{Macro}{15}{Number Fifteen\\}
\DefineInstanceOfMacroFamily{Macro}{16}{Number Sixteen\\}
\DefineInstanceOfMacroFamily{Macro}{17}{Number Seventeen\\}
\DefineInstanceOfMacroFamily{Macro}{18}{Number Eighteen\\}
\DefineInstanceOfMacroFamily{Macro}{19}{Number Nineteen\\}
\DefineInstanceOfMacroFamily{Macro}{20}{Number Twenty\\}

\ttfamily

\noindent
\verb|\CallFamilysMacro{Macro}{1}|: \CallFamilysMacro{Macro}{1}%
\verb|\CallFamilysMacro{Macro}{2}|: \CallFamilysMacro{Macro}{2}%
\verb|\CallFamilysMacro{Macro}{3}|: \CallFamilysMacro{Macro}{3}%
\verb|\CallFamilysMacro{Macro}{4}|: \CallFamilysMacro{Macro}{4}%
\verb|\CallFamilysMacro{Macro}{5}|: \CallFamilysMacro{Macro}{5}%
\verb|\CallFamilysMacro{Macro}{6}|: \CallFamilysMacro{Macro}{6}%
\verb|\CallFamilysMacro{Macro}{7}|: \CallFamilysMacro{Macro}{7}%
\verb|\CallFamilysMacro{Macro}{8}|: \CallFamilysMacro{Macro}{8}%
\verb|\CallFamilysMacro{Macro}{9}|: \CallFamilysMacro{Macro}{9}%
\verb|\CallFamilysMacro{Macro}{10}|: \CallFamilysMacro{Macro}{10}%
\verb|\CallFamilysMacro{Macro}{11}|: \CallFamilysMacro{Macro}{11}%
\verb|\CallFamilysMacro{Macro}{12}|: \CallFamilysMacro{Macro}{12}%
\verb|\CallFamilysMacro{Macro}{13}|: \CallFamilysMacro{Macro}{13}%
\verb|\CallFamilysMacro{Macro}{14}|: \CallFamilysMacro{Macro}{14}%
\verb|\CallFamilysMacro{Macro}{15}|: \CallFamilysMacro{Macro}{15}%
\verb|\CallFamilysMacro{Macro}{16}|: \CallFamilysMacro{Macro}{16}%
\verb|\CallFamilysMacro{Macro}{17}|: \CallFamilysMacro{Macro}{17}%
\verb|\CallFamilysMacro{Macro}{18}|: \CallFamilysMacro{Macro}{18}%
\verb|\CallFamilysMacro{Macro}{19}|: \CallFamilysMacro{Macro}{19}%
\verb|\CallFamilysMacro{Macro}{20}|: \CallFamilysMacro{Macro}{20}%
\verb|\CallFamilysMacro{Macro}{21}|: \CallFamilysMacro{Macro}{21}% <- This yields !!Macro undefined!!
\newpage

% This defines macros
%   \LookUpInRandomMapA1 -> Random number in range 1..20
%   \LookUpInRandomMapA2 -> Another random number in range 1..20
%   ..
%   \LookUpInRandomMapA11 -> Yet another random number in range 1..20
%
%   Any two of these macros will not expand to the same number.
%
%   In the first LaTeX-run the values will be generated via
%   \pgfmathrandominteger. In consecutive LaTeX runs they will
%   be obtained from Labels "RabdomMapA1".."RabdomMapA11"
%
\CreateMappingToDifferentRandomIntegers{11}{1}{20}{RandomMapA}{LookUpInRandomMapA}%

\noindent
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{1}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{1}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{1}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{1}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{2}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{2}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{2}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{2}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{3}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{3}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{3}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{3}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{4}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{4}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{4}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{4}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{5}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{5}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{5}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{5}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{6}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{6}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{6}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{6}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{7}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{7}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{7}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{7}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{8}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{8}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{8}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{8}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{9}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{9}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{9}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{9}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{10}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{10}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{10}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{10}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{11}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{11}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{11}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{11}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{12}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{12}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{12}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{12}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{13}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{13}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{13}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{13}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{14}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{14}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{14}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{14}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{15}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{15}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{15}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{15}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{16}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{16}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{16}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{16}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{17}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{17}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{17}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{17}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{18}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{18}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{18}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{18}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{19}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{19}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{19}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{19}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{20}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{20}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{20}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{20}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{21}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{21}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapA{21}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapA{21}}%<- This yields: !!No Mapping defined!!
\newpage

% This defines macros
%   \LookUpInRandomMapB1 -> Random number in range 1..20
%   \LookUpInRandomMapB2 -> Another random number in range 1..20
%   ..
%   \LookUpInRandomMapB8 -> Yet another random number in range 1..20
%
%   Any two of these macros will not expand to the same number.
%
%   In the first LaTeX-run the values will be generated via
%   \pgfmathrandominteger. In consecutive LaTeX runs they will
%   be obtained from Labels "RabdomMapB1".."RabdomMapB8"
%
\CreateMappingToDifferentRandomIntegers{8}{1}{20}{RandoMmapB}{LookUpInRandomMapB}%

\noindent
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{1}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{1}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{1}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{1}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{2}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{2}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{2}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{2}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{3}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{3}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{3}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{3}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{4}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{4}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{4}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{4}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{5}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{5}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{5}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{5}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{6}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{6}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{6}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{6}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{7}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{7}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{7}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{7}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{8}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{8}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{8}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{8}}%
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{9}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{9}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{9}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{9}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{10}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{10}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{10}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{10}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{11}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{11}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{11}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{11}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{12}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{12}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{12}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{12}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{13}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{13}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{13}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{13}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{14}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{14}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{14}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{14}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{15}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{15}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{15}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{15}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{16}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{16}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{16}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{16}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{17}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{17}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{17}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{17}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{18}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{18}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{18}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{18}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{19}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{19}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{19}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{19}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{20}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{20}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{20}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{20}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{21}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{21}}%<- This yields: !!No Mapping defined!!
\verb|\CallFamilysMacro{Macro}{\LookUpInRandomMapB{21}}|: \CallFamilysMacro{Macro}{\LookUpInRandomMapB{21}}%<- This yields: !!No Mapping defined!!

\end{document}

enter image description here enter image description here enter image description here

| improve this answer | |
0

It's not clear how you generate the macros, but you may enjoy this shuffling macros based on https://tex.stackexchange.com/a/224559/4427

\documentclass{article}
\usepackage{indentfirst}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\makemacros}{m}
 {
  \int_zero:N \l_jason_counter_int
  \clist_map_inline:nn { #1 }
   {
    \__jason_make_macro:nn ##1
   }
 }

\NewDocumentCommand{\permuteandprint}{+m}
 {
  \knuthshuffle_generate:n { \prop_count:N \g_knuthshuffle_identity_prop }
  \seq_map_inline:Nn \l_knuthshuffle_permutation_seq { #1 }
 }

\cs_new_protected:Nn \__jason_make_macro:nn
 {
  \cs_new:Npn #1 { #2 }
  \int_incr:N \l_jason_counter_int
  \prop_gput:NVn \g_knuthshuffle_identity_prop \l_jason_counter_int { #1 }
 }

\int_new:N \l_jason_counter_int

\prop_new:N \g_knuthshuffle_identity_prop
\prop_new:N \l_knuthshuffle_newperm_prop
\int_new:N \l_knuthshuffle_random_int

\cs_new:Nn \knuthshuffle_get_random:Nnn
 {
  \int_set:Nn #1 { \fp_eval:n { randint(#2,#3) } }
 }

\cs_new_protected:Nn \knuthshuffle_generate:n
 {
  \prop_set_eq:NN \l_knuthshuffle_newperm_prop \g_knuthshuffle_identity_prop
  \int_step_inline:nnnn { #1 } { -1 } { 2 }
   {
    \knuthshuffle_get_random:Nnn \l_knuthshuffle_random_int { 1 } { ##1 }
    \prop_get:NnN \l_knuthshuffle_newperm_prop { ##1 } \l_knuthshuffle_tempa_tl 
    \prop_get:NVN \l_knuthshuffle_newperm_prop \l_knuthshuffle_random_int \l_knuthshuffle_tempb_tl 
    \prop_put:NnV \l_knuthshuffle_newperm_prop { ##1 } \l_knuthshuffle_tempb_tl
    \prop_put:NVV \l_knuthshuffle_newperm_prop \l_knuthshuffle_random_int \l_knuthshuffle_tempa_tl
   }
  \seq_clear:N \l_knuthshuffle_permutation_seq
  \int_step_inline:nnnn { 1 } { 1 } { #1 }
   {
    \seq_put_right:Nx \l_knuthshuffle_permutation_seq
     {
      \prop_item:Nn \l_knuthshuffle_newperm_prop { ##1 }
     }
   }
  %\seq_show:N \l_knuthshuffle_permutation_seq % for debugging
 }
\ExplSyntaxOff


\makemacros{
  \aaa{Aaa Aaa},
  \bbb{Bbb Bbb},
  \ccc{Ccc Ccc},
  \ddd{DDD DDD},
  \eee{Eee},
  \fff{Ffffff},
}

\begin{document}

\section{Show the expansion}

\permuteandprint{This is ``#1''\par}

\section{Show the macros}

\permuteandprint{This is \texttt{\string#1}\par}

\end{document}

enter image description here

The argument to \permuteandprint is how you want to use the stored macros (after being permuted); #1 stands for the current stored macro.

| improve this answer | |
0

If I got your last comment right, you wish to randomly choose 30 different elements from 60000 different elements while the order in which they are chosen does matter?

The amount of possible choices corresponds to the 30th falling factorial of 60000. I.e. (60000!)/((60000-30)!). That will be a big number.

Afaik the range of numbers that can be stored in TeX' count-registers and processed by \number is from -(231 -1) to +(231 -1).


One method could be randomly choosing numbers within range 1..60000 until 30 different numbers are found. After each choice you'd need to find out whether the chosen number was already chosen in a previous choice. You don't know when this is done. With bad luck the process will take a very long time as you will often get numbers that were already chosen. That's very unlikely to happen when choosing only 30 elements from 60000 elements, but it is not completely impossible to happen.


Another method could be:

Step A:
k:=0 ;
Create a list of not-yet-chosen elements. (At the start that will be a list with 60000 elements!!!).

Step B:
If k<30 :

  • Increase k  by 1.
  • Bijectively map the elements of the list of not-yet-chosen elements to integers in range 1..(amount of elements of list of not-yet-chosen elements) and randomly find a number in that range and take the element within the list of not-yet-chosen elements mapped to that number for the kth  element of your choice. Then create a new list of not-yet-chosen elements by removing the chosen element from the list of not-yet-chosen elements. Then go back to the start of step B.

If not(k < 30 ) : Terminate as there are 30 different randomly chosen numbers.


Yet another method could be creating a subset consisting of the first k  elements of a random permutation of the n  elements, e.g., by means of the Fisher-Yates-shuffle-algorithm or the Knuth-shuffle-algorithm.
In your case you'd need to perform k  "exchanges". Within the the lth  exchange for obtaining the lth  element of that subset you can choose between 60000+1-l  elements...


Still another method could be creating the subset of the random permutation by means of Lehmer-decoding:

There are (n!)/((n-k)!)  possible choices when choosing k  different elements from n  different elements while the order of the chosen elements does matter.

Assume the n  different elements are bijectively mapped to integeral-numbers in range 0..(n-1) .

(If the elements are numbered from 1 to n , you can easily achieve such mapping for each element by subtracting 1 from the nominal-number denoting the element in question.)

Choose a random number u  within the range 0..((n!/(n-k)!)-1) . (Calculating that range might take time.)
Take u⋅((n-k)!)  for the Lehmer code of the (u⋅((n-k)!))th  permutation of n  different numbers in range 0..(n-1)  whereby the permutations are lexicographically sorted and numbered from 0 to (n!-1) .
Lehmer-decode u⋅((n-k)!)  in order to obtain that permutation.
(Lehmer-decoding is fun as it includes calculating the representation of u⋅((n-k)!)  in the factorial system which in turn implies division by all integers in range 1..nwhich takes time. In your case: n=60000  ... )
Keep only the first k  numbers from that permutation and take them for the numbers which the elements choosen are mapped to and obtain the nominal-number of each chosen element by adding 1 to each of these first k  numbers.


As you have to cope with large numbers/large amounts of elements while

  1. the range for numbers is limited when using TeX' count registers,
  2. expansion is slow when not using count registers but implementing things expandably—one could use the bigintcalc-package for this,
  3. the amount of tokens that can go into a macro argument is limited as well (this can be important when it comes to gathering huge lists within macro arguments)

, I in any case recommend not using (La)TeX for implementing this but writing an external executable program which calculates the random choice and delivers a text file choice.tex containing a sequence like:

\newcommand*\RandomChoice{%
  {<Random-number1>}{<Random-number2>}{<Random-number3>}{<Random-number4>}%
  {<Random-number5>}{<Random-number6>}{<Random-number7>}{<Random-number8>}%
  {<Random-number9>}{<Random-number10>}{<Random-number11>}{<Random-number12>}%
  {<Random-number13>}{<Random-number14>}{<Random-number15>}{<Random-number16>}%
  {<Random-number17>}{<Random-number18>}{<Random-number19>}{<Random-number20>}%
  {<Random-number21>}{<Random-number22>}{<Random-number23>}{<Random-number24>}%
  {<Random-number25>}{<Random-number26>}{<Random-number27>}{<Random-number28>}%
  {<Random-number29>}{<Random-number30>}%
}

From within a LaTeX-run such an external program can be called/executed via (La)TeX' \write18-feature if that is enabled.

You can use the LaTeX2e-kernel-macro \IfFileExists for via \write18 calling your external program and thus creating the text-file choice.tex in case it does not already exist before \input-ing it.

With some strange project, I did keep the C++-source code of a small program within a filecontents*-environment which did produce the corresponding .cpp-file on the fly. Then I used \write18 for running the C++-compiler on that .cpp-file. Then I used \write18 for exexuting the executable produced by the C++-compiler. Of course the thing wasn't platform-independent any more...

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.