2

I'm looking to randomize the order of enumerate items (which I know has a solution), but I'm also looking to fix one of the entries. In other words, I want to randomize the numbers 1-10, but have 6 be in the 6th position. Is there a solution to this?

EDIT: The code I'm working with is from Random shuffle itemize

\documentclass[12pt]{article}  
\usepackage[utf8]{inputenc}
\usepackage[english]{babel}
\usepackage{listings}
\usepackage{enumitem}

\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

\lstset{
basicstyle=\bfseries\scriptsize\tt,
}

\begin{document}
\LARGE
\begin{center}
    Do the following give categorical, discrete, or continuous responses?
\end{center}
\begin{randomList}
    \item 1

    \item 2

    \item 3

    \item 4

    \item 5

    \item 6

    \item 7

    \item 8

    \item 9

    \item 10

\end{randomList}
\end{document}
4
  • Randomise 9 of them, print the first 5, print 6, print the remaining 4? What's the point of this? Since you know, you say, how to randomise the items, what's the problem?
    – cfr
    Sep 22 '17 at 1:57
  • @cfr The problem is getting the 6 in position 6. I'll edit my current code into the question. Sep 22 '17 at 2:20
  • If you are going to use my code you should at at least up-vote it:) I quite liked what I wrote for the question you cite and it's frustrating that even though my solution is the only one that really answers the non-trivial question that was asked in that post it has only received 2 votes.... Is it only the sixth entry that you want to fix or might you sometimes want the fourth entry fixed or a variable list? Please say what you really want. I don't have time to play with this today but perhaps over the weekend.
    – user30471
    Sep 22 '17 at 8:36
  • @Andrew I don't have enough rep points to give you an up vote :(. I want to fix a specific entry, I suspect it'll be the 6th, but it could be another entry, such as the 4th. I'm writing a test, and I want to burry a specific question near the middle, while randomizing the others (the room is setup so that the students are forced to be close to each other, so the randomizing of the questions is necessary). Thanks. Sep 22 '17 at 17:24
4

OK, I have hacked the code in my previous post to allow a \fixedItem in the randomList environment. The idea of the original code is that when the environment is opened the k-th \item defines an internal macro \randomListItem@<k> and these macros are then printed out in a random order when the environment is closed. The new macro \fixedItem defines an internal macro \fixedItem@<k> and this is printed at step k if it exists. This destroys some of the "elegance" of the previous code as I have to throw in extra counters in a few places, but it is not too bad:)

With the new version, the code snippet

\begin{randomList}
    \item 1

    \item 2

    \item 3

    \fixedItem 4 fixed!

    \item 5

    \fixedItem 6 fixed!

    \fixedItem 7 fixed

    \item 8

    \item 9

    \fixedItem 10 fixed!

    \fixedItem 11 fixed!

\end{randomList}

will produce (up to a random permutation depending on the pgf seed) the list:

enter image description here

You can have arbitrarily many fixed items and they can appear anywhere in the list. As with my previous code for a random list environment, you need to have a blank line at the end of every \item-block, including the last one. The code can be used with any enumerate-like environment, including those created using the enumitem package. See my previous solution for details.

Here is the full code:

\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
\newcounter{randomListItemLength}%  number of items in the random list used to construct \randomListItem@<k>'s

% \useRandomItem{k} prints item number k
\newcommand\useRandomItem[1]{%
  \stepcounter{randomListCounter}%
  \printFixedItemIfItExists\csname randomListItem@#1\endcsname%
}
\newcommand\printFixedItemIfItExists{% prints fixedItem@<randomListCounter>} if it exits and increments the counter
  \expandafter\ifcsdef\expandafter{fixedItem@\therandomListCounter}{% insert fixed item
        \expandafter\csname fixedItem@\therandomListCounter\endcsname\stepcounter{randomListCounter}}{}%
  \expandafter\ifcsdef\expandafter{fixedItem@\therandomListCounter}{\printFixedItemIfItExists}{}% checked fixed item
}

% \setRandomItem{k} saves item number k for future use
% and builds a random permutation at the same time
\def\setRandomItem#1\par{\stepcounter{randomListCounter}\stepcounter{randomListItemLength}%
       \expandafter\protected@xdef\csname randomListItem@\therandomListCounter\endcsname{\noexpand\item#1}%
       \randomlyInsertInList{randomlyOrderedList}{\therandomListItemLength}{\therandomListCounter}
}%

% \fixedItem{k} saves item number k for future use
% and builds a random permutation at the same time
\def\fixedItem#1\par{\stepcounter{randomListCounter}%
   \expandafter\protected@xdef\csname fixedItem@\therandomListCounter\endcsname{\noexpand\item#1}%
}

\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
  % Nothing 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
    \stepcounter{randomListCounter}% check for print fixed items at the end
    \printFixedItemIfItExists%
  \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}

\begin{randomList}
    \item 1

    \item 2

    \item 3

    \fixedItem 4 fixed!

    \item 5

    \fixedItem 6 fixed!

    \fixedItem 7 fixed

    \item 8

    \item 9

    \fixedItem 10 fixed!

    \fixedItem 11 fixed!

\end{randomList}

\end{document}

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.