shuffle elements of a LaTeX3 sequence
I'd use Lua. It's much more readable.
\documentclass{article}
\usepackage{expl3}
\usepackage{luacode}
\begin{luacode*}
function shuffle(list)
for i = #list,2,-1 do
local j = math.random(i)
list[i], list[j] = list[j], list[i]
end
tex.sprint(table.concat(list,","))
end
\end{luacode*}
\ExplSyntaxOn
\cs_generate_variant:Nn \seq_gset_from_clist:Nn { Nf }
\cs_new_protected:Npn \seq_shuffle_inplace:N #1
{
\seq_gset_from_clist:Nf #1 { \lua_now_x:n { shuffle({ [[ \seq_use:Nn #1 { ]] , [[ } ]] }) } }
}
\seq_gset_from_clist:Nf \g_my_seq { 0,1,2,3,4,5,6,7,8,9 }
\seq_shuffle_inplace:N \g_my_seq
\begin{document}
\seq_use:Nnnn\g_my_seq{~and~}{,~}{,~and~}
\end{document}
Wooden version. No optimization. No “expert” writting this code.
\seq_new:N \l_alexg_origin_seq
\seq_new:N \l_alexg_destiny_seq
\int_new:N \l_alexg_random_int
\int_new:N \l_alexg_current_int
\cs_new_protected:Npn \seq_shuffle:N #1
{
\seq_set_eq:NN \l_alexg_origin_seq #1
\seq_clear:N \l_alexg_destiny_seq
\prg_replicate:nn { \seq_count:N #1 }
{
\int_set:Nn \l_alexg_random_int { \int_rand:nn { 1 } { \seq_count:N \l_alexg_origin_seq } }
\int_zero:N \l_alexg_current_int
\seq_clear:N \l_tmpa_seq
\seq_map_inline:Nn \l_alexg_origin_seq
{
\int_incr:N \l_alexg_current_int
\int_compare:nNnTF { \l_alexg_current_int } = { \l_alexg_random_int }
{ \seq_put_right:Nn \l_alexg_destiny_seq { ##1 } }
{ \seq_put_right:Nn \l_tmpa_seq { ##1 } }
}
\seq_set_eq:NN \l_alexg_origin_seq \l_tmpa_seq
}
\seq_set_eq:NN #1 \l_alexg_destiny_seq
}
Complete expl3ification of @jfbu's answer.
\cs_new_protected:Npn \seq_shuffle_inplace:N #1
{
\int_zero:N \l_tmpa_int
\seq_map_inline:Nn #1
{
\int_incr:N \l_tmpa_int
\tl_set:cn { l_jfbu_shuffle_ \int_use:N \l_tmpa_int _tl } { ##1 }
}
\int_step_inline:nnnn { \l_tmpa_int } { -1 } { 2 }
{
\int_set:Nn \l_tmpb_int { \int_rand:nn { 1 } { ##1 } }
\tl_set_eq:Nc \l_tmpa_tl { l_jfbu_shuffle_##1_tl }
\tl_set_eq:cc { l_jfbu_shuffle_##1_tl } { l_jfbu_shuffle_ \int_use:N \l_tmpb_int _tl }
\tl_set_eq:cN { l_jfbu_shuffle_ \int_use:N \l_tmpb_int _tl } \l_tmpa_tl
}
\tl_set:Nx #1 % more manual approach, ideally using \seq_set_from_clist:Nx
{
\s__seq
\int_step_function:nnnN { 1 } { 1 } { \l_tmpa_int } \__jfbu_seq_construct:n
}
}
\cs_new:Npn \__jfbu_seq_construct:n #1
{ \exp_not:N \__seq_item:n { \exp_not:v { l_jfbu_shuffle_#1_tl } } }
I literally just added \seq_shuffle:N
and \seq_gshuffle:N
to expl3
(development version: https://github.com/latex3/latex3/). From what I can tell it's about 4 times faster than other solutions here except perhaps the LuaTeX one.
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\seq_gset_from_clist:Nn\g_my_seq{0,1,2,3,4,5,6,7,8,9}
\seq_gshuffle:N \g_my_seq
\begin{document}
\seq_use:Nnnn\g_my_seq{~and~}{,~}{,~and~}
\end{document}