假设我有一个通过定义的列表\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
值⟨用户传递的列表⟩,则需要设置标志,表示不需要插入该元素\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}