Grazie del codice (ma come fai a produrlo così di getto?)
Ho trovato un’altra soluzione usando random (che uso già in altri punti). Così come è non permette la scelta del seme, ma la cosa mi interessa poco (e posso sempre aggiungerlo con \randomi=). La parte principale (\getitems) è un adattamento di un vecchio codice TeX trovato tempo fa in rete.
Mi piacerebbe avere un tuo parere
`
\documentclass[a4paper]{article}
\usepackage{ifthen}
\input{random}
\makeatletter
\newcount\i@sh
\newcount\j@sh
\newcount\sh@max
\newcounter{shuf@tot}
\newcounter{shuf@lop}
\newcommand\shuf@ch{}
\renewcommand{\theshuf@lop}{\roman{shuf@lop}}%%% costruisco la lista
\newcommand\shuf@ifch[2]{%
\ifthenelse{\not\equal{\shuf@ch}{#1}}{\stepcounter{shuf@lop}\expandafter\edef\csname item\theshuf@lop \endcsname{#2}}{}%
}\newcommand\es@item[1]{%
\edef\es@Lista{\zap@space#1 \@empty}%
\@for\shuf@ch:=\es@Lista\do{%
\shuf@ifch{}{\shuf@ch}%
}
}\newcommand{\sh@chex}[1]{
\setcounter{shuf@lop}{0}
\renewcommand{\theshuf@lop}{\roman{shuf@lop}}
\es@item{#1}
\renewcommand{\theshuf@lop}{\arabic{shuf@lop}}
\setcounter{shuf@tot}{\theshuf@lop}
}\def\printitem#1{\csname item\romannumeral#1\endcsname}
%%% la funzione di scelta nella lista #2 escludendo #1 elementi
\newcommand{\scegli}[2][0]{\sh@max=#1\sh@chex{#2}\getitems}\def\getitems{%
\i@sh=\theshuf@tot
\loop
\expandafter\let \csname flag\number\i@sh \endcsname a%
\advance\i@sh by-1
\ifnum\i@sh > 0 \repeat
\i@sh=\theshuf@tot
\loop
\setrannum{\j@sh}{1}{\theshuf@tot}%
\expandafter\ifx \csname flag\number\j@sh \endcsname a%
\expandafter\let \csname flag\number\j@sh \endcsname b% Controllo se è già stato scelto
\expandafter\edef\csname file\romannumeral\j@sh\endcsname{\csname item\romannumeral\i@sh\endcsname}
\printitem\j@sh
\advance\i@sh by-1
\fi
\ifnum\i@sh > \sh@max \repeat
}\makeatother
\begin{document}
\scegli{1,2,3,4,5,6,7,8,9,10,11,12,13,14,a,b,c}\scegli[3]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,a,b,c}
\scegli[16]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,a,b,c}
\end{document}
`
Mi pare che sia più o meno come il mio; c’è una parte davvero brutta:
`\newcommand{\sh@chex}[1]{
\setcounter{shuf@lop}{0}
\renewcommand{\theshuf@lop}{\roman{shuf@lop}}
\es@item{#1}
\renewcommand{\theshuf@lop}{\arabic{shuf@lop}}
\setcounter{shuf@tot}{\theshuf@lop}
}`
che, a parte la notevole quantità di spazi spuri, è inutilmente complicata:
`\newcommand{\sh@chex}[1]{%
\setcounter{shuf@lop}{0}%
\es@item{#1}%
\setcounter{shuf@tot}{\value{shuf@lop}}%
}`
Non occorre certo rappresentare numericamente un contatore per accedere al suo valore. 🙂
Sinceramente preferisco il mio; si tratta solo di aggiungere una corrispondenza tra gli oggetti eterogenei del tuo insieme e un insieme numerico “fisso”, diciamo {1,2,…,n}, dove n è il numero totale di oggetti.
Nella macro \@goodchoice invece di \number\c@rand che semplicemente stampa il risultato numerico, si può mettere una qualsiasi macro. Il modo più semplice è usare \csname per avere una “associative array”.
`\def\make@list#1{%
\count@=\z@ \def\temp{#1}
\@for\next:=\temp\do{\advance\count@\@ne
\expandafter\def\csname lista@\romannumeral\count@\expandafter\endcsname
\expandafter{\next}}
\chardef\listlength=\count@}
%%% ridefinizione di \@goodchoice
def\@goodchoice{\@namedef{xyz@\romannumeral\c@rand}{}%
\advance\count\z@\@ne\do@something\@rchoice}
%%% definizione dell'azione finale da eseguire con l'elemento estratto
\def\do@something{\@nameuse{lista@\romannumeral\c@rand}\space}`
Potresti adesso definire
`\newcommand\scegli[1]{\make@list{#1}%
\rchoice{1}{\list@length}{}}`
Non sono ben sicuro di aver capito a che serve l’argomento opzionale di \scegli
Ciao
Enrico