如果我有一个列表\def\Main{25, 76,38, 19, 58,29,88,44, 22, 11, 34, 17}
,其中包含 1,2,...,25 (含)内的某些数字。
如何获取包含主列表中的数字以外的所有数字 1,2,...,25 的列表?
这意味着:1,2,3,4,5,6,7,8,9,10, 12,13,14,15,16, 18,20,21, 23,24
---> 我需要这个列表以供以后使用!
\documentclass[a4paper]{article}
\usepackage{tikz}
\begin{document}
\def\Main{25, 76,38, 19, 58,29,88,44, 22, 11, 34, 17}
\let\Sub=\empty
\foreach \k in \Main{
\pgfmathparse{\k<=25 ? \k : "0"}
\ifx\empty\Sub{} \xdef\Sub{\pgfmathresult}%
\else \xdef\Sub{\Sub,\pgfmathresult}%
\fi
}
\section{Show wrong List}
\Sub
\section{Needed List}
1,2,3,4,5,6,7,8,9,10,~~~ 12,13,14,15,16,~~~ 18,~~~ 20,21,~~~ 23,24
(placed in gaps for better seeing)
\end{document}
答案1
更简单的实现expl3
。可以添加额外的接口来从列表中提取项目或循环浏览它们。
\documentclass{article}
%\usepackage{xparse} % not needed with LaTeX 2020-10-01 or later
\ExplSyntaxOn
%% first an interface to manage clists
\NewDocumentCommand{\clistset}{mm}
{
\clist_clear_new:c { l__cislist_#1_clist }
\clist_set:cn { l__cislist_#1_clist } { #2 }
}
\NewDocumentCommand{\clistcomplement}{mmO{1}m}
{% #1 = list to set, #2 = list to take from, #3 = start, #4 = end
\clist_clear_new:c { l__cislist_#1_clist }
\int_step_inline:nnn { #3 } { #4 }
{
\clist_if_in:cnF { l__cislist_#2_clist } { ##1 }
{% if the current number doesn't belong to the second list, add to the first
\clist_put_right:cn { l__cislist_#1_clist } { ##1 }
}
}
}
\NewDocumentCommand{\clistuse}{mm}
{% #1 = list, #2 = separator
\clist_use:cn { l__cislist_#1_clist } { #2 }
}
\ExplSyntaxOff
\begin{document}
\clistset{first}{25, 76,38, 19, 58,29,88,44, 22, 11, 34, 17}
\clistcomplement{second}{first}{25}
\clistcomplement{third}{first}[18]{36}
\clistuse{second}{, }
\clistuse{third}{--}
\end{document}
该\clistcomplement
命令有一个可选的第三个参数来设置起点(默认 1)。
答案2
下面提供了一个名为的宏\getmissingelements
。
\getmissingelements
将采用两个强制参数,后跟一个可选参数,指定列表的数字范围(默认为1-25
)。
两个强制参数是应存储结果的宏和主列表。
它还有一个带星号的变体,可以扩展列表一次(因此您\Main
无需使用\expandafter
它)。
它的工作原理是,首先设置一个序列来保存提供的列表,然后遍历整数范围并检查整数是否在序列中。如果不在,则将该整数添加到临时的逗号分隔列表中。遍历整数后,用户提供的宏将设置为逗号分隔列表的内容。除了最终分配给用户指定的宏之外,所有操作都在本地组中完成。
\documentclass[]{article}
\ExplSyntaxOn
\NewDocumentCommand \getmissingelements { s m m >{\SplitArgument{1}{-}}O{1-25} }
{
\IfBooleanTF {#1}
{ \cis_get_missing_elements:Nnno }
{ \cis_get_missing_elements:Nnnn }
#2 #4 {#3}
}
\msg_new:nnn { cis } { missing-value } { Missing~value.~Aborting! }
\cs_new_protected:Npn \cis_get_missing_elements:Nnnn #1#2#3#4
{
\tl_if_novalue:nTF {#3}
{ \msg_error:nn { cis } { missing-value } }
{
\group_begin:
\seq_clear:N \l_tmpa_seq
\clist_clear:N \l_tmpa_clist
\seq_set_from_clist:Nn \l_tmpa_seq {#4}
\int_step_inline:nnn {#2} {#3}
{
\seq_if_in:NnF \l_tmpa_seq {##1}
{
\clist_put_right:Nn \l_tmpa_clist {##1}
}
}
\exp_args:NNNV
\group_end:
\cs_set:Npn #1 \l_tmpa_clist
}
}
\cs_generate_variant:Nn \cis_get_missing_elements:Nnnn { Nnno }
\ExplSyntaxOff
\def\Main{0,1,2,3,4,5, 10,11, 20,21}
\begin{document}
\getmissingelements\cistmp{25, 76,38, 19, 58,29,88,44, 22, 11, 34, 17}
\cistmp
\getmissingelements*\cistmp{\Main}
\cistmp
% braces around `-2' to hide the minus from the argument splitting
\getmissingelements*\cistmp{\Main}[{-2}-7]
\cistmp
\end{document}
答案3
\Main
定义之后,我创建了 25 个宏\z1
,,\z2
...包含数字1
,,2
...
然后我读\Main
入一个数组列表\mynums
。
然后我设置一个循环,对于\mynums
数组中的每个项目,如果它小于 26,我将相应的\z?
值重新定义为空。因此,例如,如果\mynums
数组值为11
,我将重新定义\z11
为空。
\z1
然后我循环浏览修改后的、、 ...列表\z2
,并将每个值连接到一个字符串\newlist
,并根据需要在列表项之间添加逗号。
因此,最终结果在于\newlist
。
已编辑,将其全部放入宏中\getmissingnumbers
。
\documentclass{article}
\usepackage{listofitems,pgffor}
\makeatletter
\newcommand\getmissingnumbers[1]{%
\foreach\z in{1,...,25}{%
\expandafter\gdef\csname z\z\expandafter\endcsname\expandafter{\z}%
}%
\readlist*\mynums{#1}%
\foreachitem\z\in\mynums[]{%
\ifnum\z<26\relax
\expandafter\gdef\csname z\z\endcsname{}%
\fi
}%
\gdef\newlist{}%
\foreach\z in{1,...,25}{%
\if\relax\csname z\z\endcsname\relax\else
\if\relax\newlist\relax\else\g@addto@macro\newlist{,}\fi
\expandafter\g@addto@macro\expandafter\newlist\expandafter{%
\csname z\z\endcsname}%
\fi
}%
}
\makeatother
\begin{document}
\def\Main{25, 76,38, 19, 58,29,88,44, 22, 11, 34, 17}
\getmissingnumbers{\Main}
\newlist
\end{document}
答案4
为了完成,提供一个 LuaLaTeX 解决方案:
\sortandremove
将采用三个参数:前两个是限制(顺序无关紧要,因为 Lua 会处理这个),第三个是用作过滤器的列表。
%!TEX program = lualatex
\documentclass{standalone}
\usepackage{luacode}
\begin{luacode*}
userdata = userdata or {}
function userdata.sort_and_remove(a, b, ...)
local max = (a > b and a) or b
local min = (a > b and b) or a
--ConTeXt goodies
local t = table.sorted({...})
local hash = table.tohash(t)
--
local result = {}
for i = min, max do
if not hash[i] then result[#result +1] = i end
end
return table.concat(result, ", ")
end
\end{luacode*}
\newcommand\sortandremove[3]{\directlua{tex.sprint(userdata.sort_and_remove(#1, #2, #3))}}
\begin{document}
%try \sortandremove{25}{1}{...}
\sortandremove{1}{25}{25, 76,38, 19, 58,29,88,44, 22, 11, 34, 17}
\end{document}