从另一个列表中提取不同值的列表(删除重复项)

从另一个列表中提取不同值的列表(删除重复项)

假设我有一个通过定义的列表\def\zList{0,0,1,1,1,2,2,10}

如何获取0,1,2,10包含唯一/不同值的(逗号分隔的)列表0,0,1,1,1,2,2,10

有没有办法pgfmath(在更复杂的环境中我也需要整个内容 [pgfplots/-table],所以pgfmath不会太糟糕......)

在此处输入图片描述

\documentclass[a4paper]{article}
\usepackage{tikz}
\begin{document}
\def\zList{0,0,1,1,1,2,2,10}

\let\List=\empty% create List
\foreach \n  in \zList {%
\pgfmathparse{\n}%  <--- A clever method needed here
  \ifx\empty\List{} \xdef\List{\pgfmathresult}%
  \else \xdef\List{\List,\pgfmathresult}%
  \fi}
  
Show Zero List: \zList

Show List-Actual: \List

Show List-Target: 0,1,2,10
\end{document}

答案1

您可以使用以下方法删除重复项expl3

\ExplSyntaxOn
\cs_new_eq:NN \removeclistdupes \clist_remove_duplicates:N
\ExplSyntaxOff
\Removeclistdupes\List

完整的例子

\documentclass[a4paper]{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new_eq:NN \removeclistdupes \clist_remove_duplicates:N
\ExplSyntaxOff
\usepackage{tikz}

\begin{document}
\def\zList{0,0,1,1,1,2,2,10}

\let\List=\empty% create List
zList
\foreach \n  in \zList {%
\pgfmathparse{\n}%  <--- A clever method needed here
  \ifx\empty\List{} \xdef\List{\pgfmathresult}%
  \else \xdef\List{\List,\pgfmathresult}%
  \fi}
\removeclistdupes\List
  
Show Zero List: \zList

Show List-Actual: \List

Show List-Target: 0,1,2,10
\end{document}

答案2

\documentclass{article}
\usepackage{listofitems,pgffor}
\newcounter{zcount}
\newtoks\mytoks
\mytoks{}
\expandafter\def\csname zmatch0\endcsname{-9999999}% NUMBER NOT IN LIST
\begin{document}
\def\zList{0,0,1,1,1,2,2,10}
The original list is \zList

\readlist\zdata{\zList}
\foreachitem\z\in\zdata[]{%
  \gdef\ztest{F}%
  \foreach\zcnt in {0,...,\thezcount}{%
    \ifnum\z=\csname zmatch\zcnt\endcsname\relax\gdef\ztest{T}\fi%
  }%
  \if F\ztest
    \stepcounter{zcount}%
    \expandafter\gdef\csname zmatch\thezcount\expandafter\endcsname
      \expandafter{\z}%
    \expandafter\ifx\expandafter\relax\the\mytoks\relax
      \else\mytoks\expandafter{\the\mytoks,}\fi
    \mytoks\expandafter{\the\expandafter\mytoks\z}%
  \fi
}
The new list is \the\mytoks
\end{document}

在此处输入图片描述

如果你对标记列表不熟悉,那么这里有一个使用\defs 的版本,

\documentclass{article}
\usepackage{listofitems,pgffor}
\newcounter{zcount}
\expandafter\def\csname zmatch0\endcsname{-9999999}% NUMBER NOT IN LIST
\begin{document}
\def\zList{0,0,1,1,1,2,2,10}
The original list is \zList

\readlist\zdata{\zList}
\foreachitem\z\in\zdata[]{%
  \gdef\ztest{F}%
  \foreach\zcnt in {0,...,\thezcount}{%
    \ifnum\z=\csname zmatch\zcnt\endcsname\relax\gdef\ztest{T}\fi%
  }%
  \if F\ztest
    \stepcounter{zcount}%
    \expandafter\xdef\csname zmatch\thezcount\expandafter\endcsname
      \expandafter{\z}%
    \ifnum\thezcount=1\relax
      \xdef\zNewList{\csname zmatch1\endcsname}%
    \else
      \xdef\zNewList{\zNewList,\csname zmatch\thezcount\endcsname}
    \fi
  \fi
}

The new list is \zNewList
\end{document}

答案3

编辑:有人要求删去“不必要的”零。您可以使用\FPclipfp-package 执行此操作。

如果您希望使用 提供的工具进行整理tikz,您可以考虑对已构建的列表进行嵌套迭代:

\documentclass[a4paper]{article}
\usepackage[nomessages]{fp}
\usepackage{tikz}
\usetikzlibrary{math}

% pgfmanual.pdf promises a ot of things to work which often don't due to bugs.
% E.g., with tikz/pgf 3.1.1 by default there is no \ifpgfmathfloatparseactive
% and evaluation of if-expressions via \pgfmathfloattofixed seems corrupted.
% \newif\ifpgfmathfloatparseactive
% \pgfmathfloatparseactivefalse
%
% Afaik current release (the date of writing this answer is 
% August 28, 2020) is 3.1.5b.
% Seems things are fixed there.

\newcommand\PassFirstToSecond[2]{#2{#1}}%
\newif\ifalreadyinserted

\begin{document}

\newcommand\one{1}
\newcommand\two{2}
\newcommand\onecommaeight{1.8}
\newcommand*\zList{0,0,1,1,1.8,1.6754376,\one,\two,1,2,4+4,2,10,1.7,1.7,\onecommaeight,8,1.0}

\newcommand*\List{}% create List
\foreach \n  in \zList {%
    \pgfmathparse{\n}%
    \let\n=\pgfmathresult
    \FPclip{\n}{\n}%
    \expandafter\PassFirstToSecond\expandafter{\List}{%
      \def\List{}%
      \global\alreadyinsertedfalse
      \foreach \o in 
    }{%
      \tikzmath{%
        if (\o <= \n) then {{\xdef\List{\List\ifx\List\empty\else,\fi\o}};}%
                      else {{\xdef\List{\List\ifx\List\empty\else,\fi\ifalreadyinserted\else\n,\fi\o}};};%
        if (\o >= \n) then {{\global\alreadyinsertedtrue};};%
      }%
    }%
    \ifalreadyinserted\else
      \xdef\List{\List\ifx\List\empty\else,\fi\n}%
    \fi
}
  
Show Zero List: \texttt{\frenchspacing\string\zList: \meaning\zList}

Show List-Actual: \texttt{\frenchspacing\string\List: \meaning\List}

\end{document}

在此处输入图片描述

解释:

你有⟨用户传递的列表⟩\zList)以及⟨目前已创建排序列表⟩\List)。

每个元素\n⟨用户传递的列表⟩请执行下列操作:

  • 设置一个标志(\ifalreadyinserted/ \alreadyinsertedfalse/ \alreadyinsertedtrue)来指示可能需要插入该元素\n⟨目前已创建排序列表⟩

  • “查看”每个元素\o元素⟨目前已创建排序列表⟩用于查明元素\n元素⟨用户传递的列表⟩需要插入到⟨目前已创建排序列表⟩

    只要元素的值\o⟨目前已创建排序列表⟩不大于元素的值\n⟨用户传递的列表⟩,元素\n⟨用户传递的列表⟩不需要插入⟨目前已创建排序列表⟩

    如果标志仍然表明可能需要插入元素\n⟨目前已创建排序列表⟩,这是第一次发生该元素的值\o元素⟨目前已创建排序列表⟩大于元素的值\n⟨用户传递的列表⟩,元素\n⟨用户传递的列表⟩需要插入到⟨目前已创建排序列表⟩在元素之前\o⟨目前已创建排序列表⟩
    如果这是第一次发生……——需要标志来查明这是否是第一次。

    如果元素的值\o如果元素⟨目前已创建排序列表⟩大于或等于元素的值\n⟨用户传递的列表⟩,则需要设置标志,表示不需要插入该元素\n,则需要设置标志⟨用户传递的列表⟩进入⟨用户传递的列表⟩

  • 如果查看完所有元素\o⟨目前已创建排序列表⟩该标志仍然表明可能需要插入\n元素⟨用户传递的列表⟩进入⟨目前已创建排序列表⟩,则表明元素的\n⟨用户传递的列表⟩大于\o已经在的所有元素的值⟨目前已创建排序列表⟩因此\n⟨用户传递的列表⟩需要附加到⟨目前已创建排序列表⟩

答案4

为了多样性,这里有一个基于 LuaLaTeX 的解决方案。

输入字符串(例如,由 定义\zList)可能包含数字、\zList扩展为数字的宏(除了它本身)以及包含逗号分隔的数字列表的字符串。数字不必按升序排序。

\unique提取 中包含的唯一排序数字\zList

在此处输入图片描述

% !TeX program = lualatex
\documentclass{article}

%% Lua-side code
\usepackage{luacode} % for 'luacode' environment
\begin{luacode}
function string_to_table (str)
   local fields = {} -- initialize the table
   str:gsub( "([^,]*)" , function ( c ) 
                 -- strip off anyleading and trailing whitespace:
                 c = c:gsub ( "^%s*(.-)%s*$" , "%1" )
                 -- insert 'c' in 'fields'
                 table.insert ( fields , tonumber(c) )   
               end )
   return fields
end
function remove_duplicate_entries ( t ) 
   -- from https://stackoverflow.com/a/20067270/1014365
   local hash = {}
   local res = {}
   for _,v in ipairs(t) do
      if (not hash[v]) then
         res[#res+1] = v 
         hash[v] = true
      end
   end
   return res
end
function unique ( s )
   local t
   -- Convert string 's' to a Lua table:
   t = string_to_table ( s )
   -- Sort the table entries in ascending order:
   table.sort ( t , function(a,b) return a<b end)
   -- Retain the unique elements:
   t = remove_duplicate_entries ( t )
   -- Convert table back to string and print:
   tex.sprint ( table.concat ( t, "," )  )
end
\end{luacode}
%% LaTeX-side code:
\newcommand\unique[1]{\directlua{unique(\luastring{#1})}}

\begin{document}
\def\mynum{10}
\newcommand\mystr{"\mynum,0"}
\def\zList{0,10,1,1,2,2,1,0,\mynum,\mystr}

\zList

\unique{\zList}
\end{document}

相关内容