获取不在列表中的元素

获取不在列表中的元素

如果我有一个列表\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}

在此处输入图片描述

相关内容