Angenommen, ich habe eine Liste definiert über \def\zList{0,0,1,1,1,2,2,10}
.
Wie kann ich eine (durch Kommas getrennte) Liste erhalten 0,1,2,10
, die die eindeutigen/unterschiedlichen Werte in enthält 0,0,1,1,1,2,2,10
?
Gibt es vielleicht eine Möglichkeit mit pgfmath
?(Ich brauche das Ganze auch in komplexeren Kontexten [pgfplots/-table], pgfmath
wäre also nicht so schlimm ...)
\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}
Antwort1
Sie können Duplikate entfernen mitexpl3
\ExplSyntaxOn
\cs_new_eq:NN \removeclistdupes \clist_remove_duplicates:N
\ExplSyntaxOff
\Removeclistdupes\List
Ein vollständiges Beispiel
\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}
Antwort2
\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}
Wenn Sie mit Token-Listen nicht vertraut sind, gibt es hier eine Version, die \def
stattdessen s verwendet.
\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}
Antwort3
Edit: Jemand hat darum gebeten, "unnötige" Nullen zu entfernen. Das geht mit \FPclip
dem fp-Paket.
Wenn Sie das Aussortieren mit den von bereitgestellten Tools durchführen möchten tikz
, können Sie eine verschachtelte Iteration der bereits erstellten Liste in Betracht ziehen:
\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}
Erläuterung:
Du hast die⟨vom Benutzer übergebene Liste⟩( \zList
) und das⟨Bisher erstellte sortierte Liste⟩( \List
).
Mit jedem Element \n
der⟨vom Benutzer übergebene Liste⟩Mach Folgendes:
Setzen Sie ein Flag (
\ifalreadyinserted
/\alreadyinsertedfalse
/\alreadyinsertedtrue
), um anzuzeigen, dass es möglicherweise notwendig ist, dieses Element\n
in das⟨Bisher erstellte sortierte Liste⟩."Schauen Sie sich jedes Element
\o
der⟨Bisher erstellte sortierte Liste⟩um herauszufinden, ob das Element\n
der⟨vom Benutzer übergebene Liste⟩muss in das⟨Bisher erstellte sortierte Liste⟩:Solange der Wert des Elements
\o
der⟨Bisher erstellte sortierte Liste⟩ist nicht größer als der Wert des Elements\n
der⟨vom Benutzer übergebene Liste⟩, das Element\n
der⟨vom Benutzer übergebene Liste⟩muss nicht in den⟨Bisher erstellte sortierte Liste⟩.Wenn die Flagge immer noch anzeigt, dass das Element möglicherweise
\n
in das⟨Bisher erstellte sortierte Liste⟩tritt es zum ersten Mal aufdass der Wert des Elements\o
der⟨Bisher erstellte sortierte Liste⟩ist größer als der Wert des Elements\n
der⟨vom Benutzer übergebene Liste⟩, das Element\n
der⟨vom Benutzer übergebene Liste⟩muss in das⟨Bisher erstellte sortierte Liste⟩vor dem Element\o
der⟨Bisher erstellte sortierte Liste⟩.
Wenn es das erste Mal auftritt... – das Flag wird benötigt, um herauszufinden, ob es das erste Mal ist.Wenn der Wert des Elements
\o
der⟨Bisher erstellte sortierte Liste⟩ist größer oder gleich dem Wert des Elements\n
der⟨vom Benutzer übergebene Liste⟩, dann muss das Flag gesetzt werden, um anzuzeigen, dass es nicht notwendig ist, das Element\n
des⟨vom Benutzer übergebene Liste⟩in die⟨vom Benutzer übergebene Liste⟩.Wenn nach Betrachtung aller Elemente
\o
der⟨Bisher erstellte sortierte Liste⟩Die Flagge zeigt immer noch an, dass möglicherweise das Element\n
des⟨vom Benutzer übergebene Liste⟩in die⟨Bisher erstellte sortierte Liste⟩, dann zeigt dies an, dass der Wert des Elements\n
der⟨vom Benutzer übergebene Liste⟩ist größer als die Werte aller Elemente\o
, die sich bereits im⟨Bisher erstellte sortierte Liste⟩und dass daher das Element\n
der⟨vom Benutzer übergebene Liste⟩muss angehängt werden an die⟨Bisher erstellte sortierte Liste⟩.
Antwort4
Der Abwechslung halber hier eine LuaLaTeX-basierte Lösung.
Die Eingabezeichenfolge – definiert beispielsweise durch \zList
– kann Zahlen, Makros (außer \zList
sich selbst), die zu Zahlen erweitert werden, und Zeichenfolgen enthalten, die eine Liste durch Kommas getrennter Zahlen enthalten. Die Zahlen müssen nicht in aufsteigender Reihenfolge sortiert sein.
\unique
extrahiert die eindeutigen sortierten Zahlen, die in enthalten sind \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}