從另一個清單中提取不同值的清單(刪除重複項)

從另一個清單中提取不同值的清單(刪除重複項)

假設我有一個通過 定義的列表\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⟨用戶傳遞的列表⟩,那麼需要設定flag來表示不需要插入該\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}

相關內容