Extraia uma lista de valores distintos de outra lista (remova ingênuos)

Extraia uma lista de valores distintos de outra lista (remova ingênuos)

Suponha que eu tenha uma lista definida via \def\zList{0,0,1,1,1,2,2,10}.

Como posso obter uma lista (separada por vírgula) 0,1,2,10que contém os valores exclusivos/distintos em 0,0,1,1,1,2,2,10?

Existe talvez uma maneira pgfmath?(Eu também preciso de tudo em contextos mais complexos [pgfplots/-table], então pgfmathnão seria tão ruim...)

insira a descrição da imagem aqui

\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}

Responder1

Você pode remover duplicatas usandoexpl3

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

Um exemplo completo

\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}

Responder2

\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}

insira a descrição da imagem aqui

Se você não se sente confortável com listas de tokens, aqui está uma versão que usa \defs, em vez disso

\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}

Responder3

Editar: Alguém pediu para cortar zeros "desnecessários". Você pode fazer isso \FPclipno pacote fp.

Se desejar fazer a classificação com as ferramentas fornecidas por tikz, você pode considerar a iteração aninhada na lista já construída:

\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}

insira a descrição da imagem aqui

Explicação:

Você tem a⟨lista passada pelo usuário⟩( \zList) e a⟨lista ordenada criada até agora⟩( \List).

Com cada elemento \ndo⟨lista passada pelo usuário⟩faça o seguinte:

  • Defina um sinalizador ( \ifalreadyinserted/ \alreadyinsertedfalse/ \alreadyinsertedtrue) para indicar que pode ser necessário inserir esse elemento \nno⟨lista ordenada criada até agora⟩.

  • "Olhe" para cada elemento \odo⟨lista ordenada criada até agora⟩para descobrir se o elemento \ndo⟨lista passada pelo usuário⟩precisa ser inserido no⟨lista ordenada criada até agora⟩:

    Enquanto o valor do elemento \odo⟨lista ordenada criada até agora⟩não é maior que o valor do elemento \ndo⟨lista passada pelo usuário⟩, o elemento \ndo⟨lista passada pelo usuário⟩não precisa ser inserido no⟨lista ordenada criada até agora⟩.

    Se, embora o sinalizador ainda indique que pode haver necessidade de inserir o elemento \nno⟨lista ordenada criada até agora⟩, ocorre pela primeira vezque o valor do elemento \odo⟨lista ordenada criada até agora⟩é maior que o valor do elemento \ndo⟨lista passada pelo usuário⟩, o elemento \ndo⟨lista passada pelo usuário⟩precisa ser inserido no⟨lista ordenada criada até agora⟩antes do \oelemento⟨lista ordenada criada até agora⟩.
    Se ocorrer pela primeira vez...—o sinalizador é necessário para descobrir se é a primeira vez.

    Se o valor do elemento \odo⟨lista ordenada criada até agora⟩é maior ou igual ao valor do elemento \ndo⟨lista passada pelo usuário⟩, então o sinalizador precisa ser definido para indicar que não há necessidade de inserir o elemento \ndo⟨lista passada pelo usuário⟩no⟨lista passada pelo usuário⟩.

  • Se depois de examinar todos os elementos \odo⟨lista ordenada criada até agora⟩a flag ainda indica que pode haver necessidade de inserir o elemento \ndo⟨lista passada pelo usuário⟩no⟨lista ordenada criada até agora⟩, então isso indica que o valor do elemento \ndo⟨lista passada pelo usuário⟩é maior que os valores de todos os elementos \oque já estão no⟨lista ordenada criada até agora⟩e que, portanto, o elemento \ndo⟨lista passada pelo usuário⟩precisa ser anexado ao⟨lista ordenada criada até agora⟩.

Responder4

Para variar, aqui está uma solução baseada em LuaLaTeX.

A string de entrada - definida por, digamos, \zList- pode conter números, macros (exceto \zListela mesma) que se expandem para números e strings que contêm uma lista de números separados por vírgula. Os números não precisam ser classificados em ordem crescente.

\uniqueextrai os números classificados exclusivos contidos em \zList.

insira a descrição da imagem aqui

% !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}

informação relacionada