假設我有一個通過 定義的列表\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}
如果您對標記列表不滿意,那麼這裡有一個使用\def
s 的版本,而不是
\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
編輯:有人要求剪掉「不必要的」零。您可以使用\FPclip
fp-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}