Estoy buscando ideas sobre la siguiente tarea. Quiero ordenar las entradas en \listb
aquellas en \lista
. No siempre se puede suponer que sólo los elementos de \lista
están en \listb
; tampoco se puede suponer que todos los elementos de \lista
estén en \listb
.
\def\lista{a,b,c,d} % no 'e,f,g,h' in \lista
\def\listb{c,e,a,h,f,g,b} % no 'd' in \listb
Aquí quiero \listb
convertirme {a,b,c,e,h,f,g}
. Nota: e,h,f,g
en los resultados \listb
se debe seguir su 'ordenamiento parcial' en el original \listb
, es decir, cómo estaban ordenados en el original \listb
.
Respuesta1
TeX simple (aunque funcionaría en LaTeX, por supuesto)
\def\lista{a,b,c,d}
\def\listb{c,e,a,h,f,g,b}
\def\x#1#2,{\ifx\relax#2\else
\expandafter\let\csname #1-#2\endcsname\hbox
\expandafter\x\expandafter#1\fi}
\def\y#1#2#3,{\ifx\relax#3\else
\expandafter\ifx\csname #2-#3\endcsname#1,#3\fi
\expandafter\y\expandafter#1\expandafter#2\fi}
\def\z#1,{}
\expandafter\x\expandafter a\lista,\relax,
\expandafter\x\expandafter b\listb,\relax,
\edef\listb{%
\expandafter\z\romannumeral`\x%
\expandafter\y\expandafter\hbox\expandafter b\lista,\relax,%
\expandafter\y\expandafter\relax\expandafter a\listb,\relax,}
\show\listb
\bye
This is pdfTeX, Version 3.1415926-2.4-1.40.13 (TeX Live 2012)
restricted \write18 enabled.
entering extended mode
(./sort111.tex
> \listb=macro:
->a,b,c,e,h,f,g.
l.19 \show\listb
?
)
No pages of output.
Respuesta2
En primer lugar, me disculpo por mi intento de novato.
Aquí hay una humilde idea que tuve con expl3
:
\documentclass{article}
\usepackage{expl3}
\begin{document}
\def\lista{a,b,c,d}
\def\listb{c,e,a,h,f,g,b}
\ExplSyntaxOn
\clist_new:N \l_ahmed_clist
\clist_map_inline:Nn \lista
{
\clist_if_in:NnT \listb { #1 }
{
\clist_put_right:Nn \l_ahmed_clist { #1 }
}
}
\clist_concat:NNN \listb \l_ahmed_clist \listb
\clist_remove_duplicates:N \listb
\ExplSyntaxOff
\texttt{\meaning\listb}
\end{document}
La salida:
Espero que ayude de alguna manera.:)
Respuesta3
Aquí está la solución de David Carlisle. Mi única preocupación es el aumento exponencial en la cantidad de controles definidos, incluso con el recolector de basura (grupo local) que he usado.
\def\listb{c,e,a,h,f,g,b} ->
3601 multiletter control sequences out of 15000+200000
\def\listb{c,e,a,h,f,g,b,i,j,k} ->
3607 multiletter control sequences out of 15000+200000
Lo he generalizado para aceptar analizadores de listas arbitrarios.
\documentclass{article}
\makeatletter
% \SortToMatchGivenList[<parser>]{<master list cmd>}{<user list cmd>}
\protected\def\SortToMatchGivenList{\@testopt\S@rtToMatchGivenList,}
\def\S@rtToMatchGivenList[#1]#2#3{%
\begingroup
% Define temporary macros of elements of master and user lists:
\def\x##1##2#1{%
\ifx\relax##2\else
\expandafter\let\csname ##1-\detokenize{##2}\endcsname\noboundary
\expandafter\x\expandafter##1%
\fi
}%
% Insert elements of master list if they appear in the user list,
% and insert elements of user list if they don't exist in master list:
\def\y##1##2##3#1{%
\ifx\relax##3\else
\expandafter\ifx\csname ##2-\detokenize{##3}\endcsname##1#1##3\fi
\expandafter\y\expandafter##1\expandafter##2%
\fi
}%
% Gobble some remnant code when building the sorted user list:
\def\z##1#1{}%
\expandafter\x\expandafter a#2#1\relax#1%
\expandafter\x\expandafter b#3#1\relax#1%
\edef#3{%
\expandafter\z\romannumeral`\x%
\expandafter\y\expandafter\noboundary\expandafter b#2#1\relax#1%
\expandafter\y\expandafter\relax\expandafter a#3#1\relax#1%
}%
\edef\x{\endgroup\def\noexpand#3{#3}}\x
}
\makeatother
\def\lista{a,b,c,d}
\def\listb{c,e,a,h,f,g,b}
\SortToMatchGivenList\lista\listb
\show\listb
\begin{document}
x
\end{document}
El siguiente enfoque evita definir una gran cantidad de macros temporales, pero (como el de Paulo Cereda) es más lento que el de David Carlisle.
\documentclass{article}
\makeatletter
% \SortToMatchGivenList[<parser>]{<master list cmd>}{<user list cmd>}
\protected\def\SortToMatchGivenList{\@testopt\S@rtToMatchGivenList,}
\def\S@rtToMatchGivenList[#1]#2#3{%
\begingroup
\def\tempe##1##2{%
\def\do####1#1{%
\ifx\do####1\else
\if\relax\detokenize{####1}\relax
\let\next\do
\else
\edef\next{\unexpanded{##2\do}}%
\fi
\expandafter\next
\fi
}%
\expandafter\do##1#1\do#1%
}%
\def\tempc##1{\unexpanded\expandafter{##1}}%
\def\tempd##1##2{%
\@expandtwoargs\in@
{#1\detokenize{##1}#1}{#1\detokenize\expandafter{##2}#1}%
}%
\def\tempa{}\def\tempb{}%
\tempe{#2}{%
\tempd{##1}{#3}%
\ifin@
\edef\tempa{%
\tempc\tempa\ifx\tempa\@empty\else#1\fi
\unexpanded{##1}}%
\fi
}%
\tempe{#3}{%
\tempd{##1}\tempa
\ifin@\else
\edef\tempb{%
\tempc\tempb\ifx\tempb\@empty\else#1\fi
\unexpanded{##1}%
}%
\fi
}%
\edef\tempa{\endgroup
\edef\noexpand#3{%
\noexpand\unexpanded{\tempc\tempa#1\tempc\tempb}%
}%
}%
\tempa
}
\makeatother
\def\lista{a,b,c,d}
\def\listb{c,e,a,h,f,g,b}
\SortToMatchGivenList\lista\listb
\show\listb
\begin{document}
x
\end{document}