Get elements which are not in a list
A simpler implementation with expl3
. Additional interfaces can be added for extracting items from lists or cycling through them.
\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}
The \clistcomplement
command has an optional third argument to set the starting point (default 1).
After \Main
is defined, I create 25 macros \z1
, \z2
, ... containing the numbers 1
, 2
, ...
Then I read \Main
into a array list \mynums
.
Then I set up a loop, and for each item in the \mynums
array, if it is less than 26, I redefine the corresponding \z?
value to nothing. So, for example, if the \mynums
array value were 11
, I redefine \z11
to nothing.
Then I cycle through the revised list of \z1
, \z2
, ... and concatenate each value to a string \newlist
, adding a comma between list items, as needed.
The final result, therefore, resides in \newlist
.
EDITED to put it all into a macro \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}
The following provides a macro named \getmissingelements
.
\getmissingelements
will take two mandatory arguments followed by one optional argument specifying the number range for your list (defaulting to 1-25
).
The two mandatory arguments are the macro in which the result should be stored and the main list.
It also has a starred variant which will expand the list once (so you can use \Main
without the need to \expandafter
it).
It works by first setting a sequence to hold the provided list, then steps through the integer range and checks whether the integer is in the sequence. If it isn't that integer gets added to a temporary comma separated list. After the stepping through the integers the user provided macro will be set to the contents of the comma separated list. All except the final assignment to the user specified macro is done locally in a group.
\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}