这里有考试题目列表(例如 1-20)。该列表分为两部分(1-10、11-20)。试卷包含两个问题,第一个来自第一部分,第二个来自第二部分。这些问题必须随机选择且不重复。随机选择且不重复的问题之前已使用\pgfmathdeclarerandomlist
命令解决。
但考试之前生成的试题列表必须按顺序显示。因此列表定义为:
\listadd{\mIqlist}{}%
\forcsvlist{\listadd\mIqlist}{{This, is},{is},{a},{very},{long},{text},{split},{in},{many}}
\listadd{\mIIqlist}{}%
\forcsvlist{\listadd\mIIqlist}{{than},{thirty},{items},{in},{here,}{but},{he},{did},{not}}
出于随机目的:
%вопросы первого блока
\newcounter{firsttotal}
\newcounter{firstcurr}
\setcounter{firsttotal}{9} %общее кол-во вопросов должно совпадать с кол-вом вопросов в списке
\newcommand\declarefirst{
\pgfmathdeclarerandomlist{firstlist}{\mIqlist}}
\declarefirst
%вопросы второго блока
\newcounter{secondtotal}
\newcounter{secondcurr}
\setcounter{secondtotal}{9} %общее кол-во вопросов должно совпадать с кол-вом вопросов в списке
\newcommand\declaresecond{
\pgfmathdeclarerandomlist{secondlist}{\mIIqlist}}
\declaresecond
%макрос \prunelist для удаления уже выбраных из списка вопросов для избежания повторений в первой итерации
\makeatletter
\def\prunelist#1{
\expandafter\edef\csname pgfmath@randomlist@#1\endcsname
{\the\numexpr\csname pgfmath@randomlist@#1\endcsname-1\relax}
\count@\pgfmath@randomtemp
\loop
\expandafter\let
\csname pgfmath@randomlist@#1@\the\count@\expandafter\endcsname
\csname pgfmath@randomlist@#1@\the\numexpr\count@+1\relax\endcsname
\ifnum\count@<\csname pgfmath@randomlist@#1\endcsname\relax
\advance\count@\@ne
\repeat}
\makeatother
%печатать вопрос из первого списка (выбирается случайным образом)
\newcommand\printfirst{
\pgfmathrandomitem{\z}{firstlist}
\z
\prunelist{firstlist}
\addtocounter{firstcurr}{1}
\ifnum \value{firstcurr} = \value{firsttotal} \setcounter{firstcurr}{0}\declarefirst \fi
}
%печатать вопрос из второго списка (выбирается случайным образом)
\newcommand\printsecond{
\pgfmathrandomitem{\z}{secondlist}
\z
\prunelist{secondlist}
\addtocounter{secondcurr}{1}
\ifnum \value{secondcurr} = \value{secondtotal} \setcounter{secondcurr}{0}\declaresecond \fi
}
在文档顺序列表中显示为:
\begin{enumerate}[label={\arabic*.}]
\renewcommand*{\do}[1]{\item {#1}}
\dolistloop{\mIqlist}
\dolistloop{\mIIqlist}
\end{enumerate}
考试票上有:
\forloop{ct}{0}{\value{ct} < \value{TotalNum}}
{
....
1.\printfirst \newline\newline
2.\printsecond \newline
....
}
但编译时出现错误:
! Missing $ inserted.
<inserted text>
$
l.101 }
%forloop
当我尝试\printfirst
或时发生此错误\printsecond
。据我了解,此错误与列表分隔符有关|
。我该如何修复它?
答案1
在 LaTeX 中处理数组的最简单方法是使用\csname ...\endcsname
。(您也可以使用xstring
包,但这样速度更快,尽管不太好看。)问题是 必须在或\csname
之类的东西之前展开,导致出现很多s。此外,不是合法的宏名称,只能使用 来实现。\let
\xdef
\expandafter
\index0
\csname
\documentclass{article}
\usepackage{tikz}
\newcommand{\mylist}{}% reserve global name
\begin{document}
\begin{tikzpicture}{overlay}% ignore spaces
\foreach \i in {0,...,5} {\expandafter\xdef\csname index\i\endcsname{\i}}% create indexes
\foreach \i in {0,...,5} {% randomise (last step redundant)
\pgfmathparse{int(random(\i,5))}%
\let\j=\pgfmathresult
\expandafter\let\expandafter\tempa\csname index\i\endcsname
\expandafter\let\expandafter\tempb\csname index\j\endcsname
\global\expandafter\let\csname index\i\endcsname=\tempb
\global\expandafter\let\csname index\j\endcsname=\tempa
}%
\xdef\mylist{\csname index0\endcsname}% create comma delimited list
\foreach \i in {1,...,5} {\xdef\mylist{\mylist,\csname index\i\endcsname}}%
\end{tikzpicture}
\noindent\mylist
\end{document}
答案2
以下是使用 Knuth shuffle 算法的实现(https://tex.stackexchange.com/a/344488/4427)
\documentclass{article}
\usepackage[a6paper]{geometry}
\usepackage{xparse}
\ExplSyntaxOn
% user level commands
\NewDocumentCommand{\definefirstlist}{m}
{
\__konstantin_define_list:Nn \g_konstantin_firstlist_prop { #1 }
}
\NewDocumentCommand{\definesecondlist}{m}
{
\__konstantin_define_list:Nn \g_konstantin_secondlist_prop { #1 }
}
\NewDocumentCommand{\printlists}{ }
{
\section*{First~List}
\__konstantin_print_list:N \g_konstantin_firstlist_prop
\section*{Second~List}
\__konstantin_print_list:N \g_konstantin_secondlist_prop
}
\NewDocumentCommand{\maketickets}{}
{
% compute the number of questions
\int_set:Nn \l__konstantin_index_int
{
\int_min:nn { \prop_count:N \g_konstantin_firstlist_prop }
{ \prop_count:N \g_konstantin_secondlist_prop }
}
% generate the identity permutation
\int_step_inline:nnnn { 1 } { 1 } { \l__konstantin_index_int }
{
\prop_gput:Nnn \g_knuthshuffle_identity_prop { ##1 } { ##1 }
}
% generate a first permutation
\knuthshuffle_generate:n { \l__konstantin_index_int }
\seq_set_eq:NN \l_konstantin_firstquestion_seq \l_knuthshuffle_permutation_seq
% generate a second permutation
\knuthshuffle_generate:n { \l__konstantin_index_int }
\seq_set_eq:NN \l_konstantin_secondquestion_seq \l_knuthshuffle_permutation_seq
% print the tickets
\int_step_inline:nnnn { 1 } { 1 } { \l__konstantin_index_int }
{
\konstantin_ticket:n { ##1 }
}
}
% variables
\int_new:N \l__konstantin_index_int
\prop_new:N \g_konstantin_firstlist_prop
\prop_new:N \g_konstantin_secondlist_prop
% internal functions
\cs_new_protected:Nn \__konstantin_define_list:Nn
{
\int_zero:N \l__konstantin_index_int
\tl_map_inline:nn { #2 }
{
\int_incr:N \l__konstantin_index_int
\prop_gput:Nfn #1 { \int_to_arabic:n { \l__konstantin_index_int } } { ##1 }
}
}
\cs_generate_variant:Nn \prop_gput:Nnn { Nf }
\cs_new_protected:Nn \__konstantin_print_list:N
{
\int_step_inline:nnnn { 1 } { 1 } { \prop_count:N #1 }
{
\noindent
##1.~
\prop_item:Nn #1 { ##1 }
\par
}
}
\cs_new_protected:Nn \konstantin_ticket:n
{
\clearpage
\ticketheader{#1}
\par
\noindent\textbf{Question~1}:\\
\prop_item:Nx \g_konstantin_firstlist_prop
{
\seq_item:Nn \l_konstantin_firstquestion_seq {#1}
}
\par
\vspace*{\fill}
\noindent\textbf{Question~2}:\\
\prop_item:Nx \g_konstantin_secondlist_prop
{
\seq_item:Nn \l_konstantin_secondquestion_seq {#1}
}
\par
\vspace*{\fill}
}
\cs_generate_variant:Nn \prop_item:Nn { Nx }
%%% the Knuth shuffle macros https://tex.stackexchange.com/a/344488/4427
\prop_new:N \g_knuthshuffle_identity_prop
\prop_new:N \l_knuthshuffle_newperm_prop
\int_new:N \l_knuthshuffle_random_int
\seq_new:N \l_konstantin_firstquestion_seq
\seq_new:N \l_konstantin_secondquestion_seq
\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
% define here the header for the question tickets
\newcommand{\ticketheader}[1]{% #1 is the ticket number
\begin{center}
\large\bfseries Ticket #1
\end{center}
\bigskip
}
% define the list of questions
\definefirstlist{
{This, is}
{is}
{a}
{very}
{long}
{text}
{split}
{in}
{many}
}
\definesecondlist{
{than}
{thirty}
{items}
{in}
{here}
{but}
{he}
{did}
{not}
}
\begin{document}
\printlists
\maketickets
\end{document}