Here's an implementation of the Knuth shuffle algorithm with expl3
.
\documentclass{article}
\usepackage{amsmath,xparse}
\input{random}
\ExplSyntaxOn
\cs_new_eq:NN \knuthshuffle_get_random:Nnn \setrannum
\tl_new:N \l_knuthshuffle_tempa_tl
\tl_new:N \l_knuthshuffle_tempb_tl
\int_new:N \l_knuthshuffle_random_int
\prop_new:N \l_knuthshuffle_newperm_prop
\prop_new:N \g_knuthshuffle_identity_prop % the identity
\seq_new:N \l_knuthshuffle_permutation_seq
\int_step_inline:nnnn { 1 } { 1 } { 100 }
{
\prop_gput:Nnn \g_knuthshuffle_identity_prop { #1 } { #1 }
}
\NewDocumentCommand{\generatepermutation}{m}
{
\knuthshuffle_generate:n { #1 }
}
\NewDocumentCommand{\printpermutation}{}
{
\left(
\int_step_inline:nnnn { 1 } { 1 } { \seq_count:N \l_knuthshuffle_permutation_seq }
{
\begin{array}{c}
##1 \\ \seq_item:Nn \l_knuthshuffle_permutation_seq { ##1 }
\end{array}
}
\right)
}
\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
\begin{document}
\generatepermutation{20}
\[
\printpermutation
\]
\end{document}
The permutation is stored in a sequence, then it's up to you what to do with it. I added a \printpermutation
macro just to show how to print the most recently generated permutation.

The tools I use are
A fixed property list representing the identity permutation on the numbers from 1 to 1000
A loop from the last place downward; at step k, a random number r between 1 and k is generated thanks to random.tex
by D. Arsenau (let's hope it's integrated soon in expl3
); the element at place k is swapped with the element at place r;
Another loop loads a sequence with the so determined elements, for further processing.
The identity is defined up to 100, which should be a sufficient bound and keeps processing time down.
There is a faster way (which wastes more memory, though), using a \csname
trick. The previous solution was in the spirit of showing the available tools with a toy problem, rather than looking for an efficient implementation.
\documentclass{article}
\usepackage{amsmath,xparse}
\input{random}
\ExplSyntaxOn
\cs_new_eq:NN \knuthshuffle_get_random:Nnn \setrannum
\tl_new:N \l_knuthshuffle_tempa_tl
\tl_new:N \l_knuthshuffle_tempb_tl
\int_new:N \l_knuthshuffle_random_int
\seq_new:N \l_knuthshuffle_permutation_seq
\NewDocumentCommand{\generatepermutation}{m}
{
\knuthshuffle_generate:n { #1 }
}
\NewDocumentCommand{\printpermutation}{}
{
\left(
\int_step_inline:nnnn { 1 } { 1 } { \seq_count:N \l_knuthshuffle_permutation_seq }
{
\begin{array}{c}
##1 \\ \seq_item:Nn \l_knuthshuffle_permutation_seq { ##1 }
\end{array}
}
\right)
}
\cs_new_protected:Nn \knuthshuffle_generate:n
{
\int_step_inline:nnnn { 1 } { 1 } { #1 }
{
\tl_clear_new:c { l_knuthshuffle_##1_element_tl }
\tl_set:cn { l_knuthshuffle_##1_element_tl } { ##1 }
}
\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 }
\tl_set_eq:Nc \l_knuthshuffle_tempa_tl
{ l_knuthshuffle_##1_element_tl }
\tl_set_eq:Nc \l_knuthshuffle_tempb_tl
{ l_knuthshuffle_ \int_to_arabic:n \l_knuthshuffle_random_int _element_tl }
\tl_set_eq:cN { l_knuthshuffle_##1_element_tl }
\l_knuthshuffle_tempb_tl
\tl_set_eq:cN { l_knuthshuffle_ \int_to_arabic:n \l_knuthshuffle_random_int _element_tl }
\l_knuthshuffle_tempa_tl
}
\seq_clear:N \l_knuthshuffle_permutation_seq
\int_step_inline:nnnn { 1 } { 1 } { #1 }
{
\seq_put_right:Nv \l_knuthshuffle_permutation_seq { l_knuthshuffle_##1_element_tl }
}
% \seq_show:N \l_knuthshuffle_permutation_seq % for debugging
}
\ExplSyntaxOff
\begin{document}
\generatepermutation{20}
\[
\printpermutation
\]
\end{document}
The values are stored in an associative array using an array of token list variables, which makes addressing fast, at the expense of memory usage.

The same in Plain TeX:
\input random
\newcount\myrandom
\newcount\tempcount
\def\generatepermutation#1{%
\def\lastlength{#1}%
\tempcount=0
\loop\ifnum\tempcount<#1\relax
\advance\tempcount 1
\expandafter\edef\csname shuffle\the\tempcount element\endcsname{\the\tempcount}%
\repeat
\loop\ifnum\tempcount>1
\setrannum\myrandom{1}{\tempcount}
\edef\tempa{\csname shuffle\the\tempcount element\endcsname}%
\edef\tempb{\csname shuffle\the\myrandom element\endcsname}%
\expandafter\edef\csname shuffle\the\tempcount element\endcsname{\tempb}%
\expandafter\edef\csname shuffle\the\myrandom element\endcsname{\tempa}%
\advance\tempcount -1
\repeat
}
\long\def\gobble#1{}
\def\printpermutation{%
\left(
\def\tempa{\gobble}%
\def\tempb{\gobble}%
\tempcount=0
\loop\ifnum\tempcount<\lastlength
\advance\tempcount 1
\edef\tempa{\tempa & \the\tempcount}%
\edef\tempb{\tempb & \csname shuffle\the\tempcount element\endcsname}%
\repeat
\vcenter{\tabskip=3pt\halign{&\hfil##\hfil\cr\tempa\cr\tempb\cr}}
\right)
}
\generatepermutation{20}
$$
\printpermutation
$$
\bye
pgffor
,etoolbox
etc. A lot of packages exist actually for 'programming'.