如何对字母数字列表进行排序

如何对字母数字列表进行排序

我一直在尝试寻找一个包或一种方法,以简单的方式在 TeX/LaTeX 中对名称列表进行排序。我尝试了負責包,并查看了 LaTeX3 中的一些新宏,但都没有取得很大的成功。

我想到使用 MakeIndex 程序进行排序和分类。每个发行版都提供该程序,而且 LaTeX 类非常短,很容易被破解,大约只有 36 行(包括我可以删除的词汇表宏),并且在基本书籍或文章类中还有一些用于样式的定义。

这是一个最简单的例子,按职业(类别)对姓名列表进行排序。

\documentclass[11pt]{article}
\usepackage{makeidx}
\def\addName#1#2{\index{Name!#1}\index{#2!#1}}
\makeindex
\begin{document}
\renewcommand{\indexname}{Famous and Infamous Sorted People}
\addName{Leslie Lamport}{Computer Scientist} 
\addName{Donald Knuth}{Computer Scientist}
\addName{Tim Berners Lee}{Computer Scientist}
\addName{Brian Kernighan}{Computer Scientist}
\addName{Noam Chomsky}{Linguist}
\addName{Yiannis Lazarides}{Lifelong Trainee \protect\TeX nician}
\addName{Leonard Euler}{Mathematician}
\addName{Carl Friendrich Gauss}{Mathematician}
\addName{August Ferdinard M\"{o}bius}{Mathematician}

%% Importing the .ind file rather than use \printindex
%% so we do not need to redefine the command
%% 
\input{indextest.ind}

\begin{verbatim}
\begin{theindex}
\item Lifelong Trainee \TeX nician
    \subitem Yiannis Lazarides, 1
  \item Linguist
    \subitem Noam Chomsky, 1 
\end{theindex}
\end{verbatim}
\end{document}

这是个好主意吗?有没有专门用于字母数字排序的软件包?我知道使用外部脚本可以轻松完成,但我正在寻找 TeX/LaTeX 解决方案。你认为这是一个好方法吗?

答案1

我没有查看 Charles 的代码,因为我想看看实现一个可扩展的通用排序宏有多难。事实证明,以连续传递风格实现起来或多或少是比较简单的。

\documentclass{article}
\usepackage{etoolbox}
\makeatletter
% #1 - comparator
% #2 - token list to sort
\newcommand\sort[2]{%
        \ifstrempty{#2}
        {}% else
        {%
                \sort@begin#1{}#2\sort@s\sort@begin
        }%
}

% helpers
\def\sort@s{\sort@s}
\def\ifsort@s#1{%
        \ifx\sort@s#1%
                \expandafter\@firstoftwo
        \else
                \expandafter\@secondoftwo
        \fi
}

% #1 - comparator
% #2 - tokens processed so far
% #3 - smallest token so far
% #4 - rest of the list
\def\sort@begin#1#2#3#4\sort@begin{%
        \ifsort@s{#4}
        {%
                \sortend{#3}%
                \sort#1{#2}%
        }% else
        {%
                \sort@go#1{#2}{#3}#4\sort@go
        }%
}

% #1 - comparator
% #2 - tokens processed so far
% #3 - smallest token so far
% #4 - token under consideration
% #5 - rest of the list
\def\sort@go#1#2#3#4#5\sort@go{%
        #1{#3}{#4}{\sort@output#1{#2}{#5}}%
}
% #1 - comparator
% #2 - tokens processed so far
% #3 - rest of the list
% #4 - smaller of the two tokens
% #5 - larger of the two tokens
\def\sort@output#1#2#3#4#5{%
        \ifsort@s{#3}
        {%
                \sortoutput{#4}%
                \sort#1{#2{#5}}%
        }% else
        {%
                \sort@begin#1{#2{#5}}{#4}#3\sort@begin
        }%
}

\def\sort@numlt#1#2#3{%
        \ifnumcomp{#1}<{#2}
        {#3{#1}{#2}}% else
        {#3{#2}{#1}}%
}

\def\sort@numgt#1#2#3{%
        \ifnumcomp{#1}>{#2}
        {#3{#1}{#2}}% else
        {#3{#2}{#1}}%
}

\def\sort@alpha#1#2#3{%
        \ifnumcomp{\pdfstrcmp{#1}{#2}}<{0}
        {#3{#1}{#2}}% else
        {#3{#2}{#1}}%
}

\newcommand*\sortnumlt{\sort\sort@numlt}
\newcommand*\sortnumgt{\sort\sort@numgt}
\newcommand*\sortalpha{\sort\sort@alpha}
\makeatother

% Change these to change out the sort outputs.
\newcommand*\sortoutput[1]{#1, }
\newcommand*\sortend[1]{#1.}
\begin{document}
\sortnumgt{87632147{55}9{8/2}}

\sortalpha{{Goodbye}{Cruel}{World}}

\renewcommand*\sortoutput[1]{#1}
\renewcommand*\sortend[1]{#1}
\edef\temp{\sortnumlt{87632147{55}9}}
\texttt{\meaning\temp}
\end{document}

我希望代码可读性强。我尝试记录每个函数的参数。特别是, 的第一个参数\sort是比较器控制序列,必须采用三个参数。前两个是以下列表中要比较的两个元素,第三个是延续。基本上,比较器应该根据“小于”扩展为#3{#1}{#2}或。#3{#2}{#1}#1#2

我已经实现了三个这样的比较器。前两个比较数字列表,而第三个使用 进行字母数字字符串比较\pdfstrcmp。由于数字比较使用,\ifnumcomp因此etoolbox您可以对元素使用任意算术表达式,因此{8/2}在列表中。

最后,为了表明这是可扩展的(至少当比较器、\sortoutput和为时它是可扩展\sortend的),\temp使用来定义\edef,并且对其含义进行排版以确保它已被设置为适当的值:macro:->12346778955

请注意,将这些宏串联起来也很简单,这样就可以在同一个扩展中使用多个宏\sortoutput。我只是在编写完其余所有代码(或多或少)后才想到添加这些宏。\sortend\sorts

进一步注意,这是选择排序,因此需要Θn2)时间,即使在最好的情况下。然而,这是 TeX,它每次都必须为每个参数构建标记列表,我认为这种实现实际上是Θn3)时间。所以不要在大型​​列表上尝试。

答案2

以下肯定适用于列表,但我不确定如何将其扩展为多个排序列表。

\documentclass[a4paper,12pt]{report}
\usepackage{datatool}
\usepackage[top=2cm, bottom=2cm, left=1cm, right=1cm]{geometry}
\usepackage[spanish]{babel}
\usepackage{amsfonts,amssymb,amsmath}

\newcommand{\sortitem}[2]{%
  \DTLnewrow{list}%
  \DTLnewdbentry{list}{label}{#1}%
  \DTLnewdbentry{list}{description}{#2}%
}

\newenvironment{sortedlist}{%
  \DTLifdbexists{list}{\DTLcleardb{list}}{\DTLnewdb{list}}%
}{%
  \DTLsort{label}{list}%
  \begin{description}%
    \DTLforeach*{list}{\theLabel=label,\theDesc=description}{%
      \item[\theLabel] \theDesc }%
  \end{description}%
}

\begin{document}
\begin{sortedlist}
\sortitem{Leonard Euler}{Mathematician}
\sortitem{Carl Friedrich Gauss}{Mathematician}
\sortitem{August Ferdinand M"\obius}{Mathematician}
\end{sortedlist}
\end{document}

答案3

如果您愿意使用 LuaLaTeX,那么您应该可以从 ConTeXt MkIV 移植各种特定于语言的排序函数。例如,请参阅

答案4

我开始使用 TH 的代码,发现它需要根据我的用例进行一些调整。具体来说,我希望能够对\par其中的内容进行排序,并且希望排序顺序是基于\ref经过一番努力,我终于找到了一些方法,并认为值得在这里分享我的努力成果。使用它的示例文档如下所示:

\documentclass{article}
\usepackage{sort}
\begin{document}
\newcounter{foo}
\refstepcounter{foo}\label{a}
\refstepcounter{foo}\label{b}

\begin{trivlist}
    \sortref{%
        {{a}{Text with some proofs about part a

        in multiple paragraphs!}}%
        {{b}{Proofs about

        the other part}}%
    }
\end{trivlist}
\end{document}

这两个证明将根据 s 的\label出现顺序自动重新排序。主要区别在于增加了\long几个位置,使用\newcommand代替\newcommand*,并添加了一个新的\sortoutput使用\getrefnumber(注意从其参数中修剪)。这些更改后\par的完整内容为:sort.sty

\usepackage{etoolbox}
\usepackage{refcount}
\makeatletter
% #1 - comparator
% #2 - token list to sort
\newcommand\sort[2]{%
        \ifstrempty{#2}
        {}% else
        {%
                \sort@begin#1{}#2\sort@s\sort@begin
        }%
}

% helpers
\def\sort@s{\sort@s}
\long\def\ifsort@s#1{%
        \ifx\sort@s#1%
                \expandafter\@firstoftwo
        \else
                \expandafter\@secondoftwo
        \fi
}

% #1 - comparator
% #2 - tokens processed so far
% #3 - smallest token so far
% #4 - rest of the list
\long\def\sort@begin#1#2#3#4\sort@begin{%
        \ifsort@s{#4}
        {%
                \sortend{#3}%
                \sort#1{#2}%
        }% else
        {%
                \sort@go#1{#2}{#3}#4\sort@go
        }%
}

% #1 - comparator
% #2 - tokens processed so far
% #3 - smallest token so far
% #4 - token under consideration
% #5 - rest of the list
\long\def\sort@go#1#2#3#4#5\sort@go{%
        #1{#3}{#4}{\sort@output#1{#2}{#5}}%
}
% #1 - comparator
% #2 - tokens processed so far
% #3 - rest of the list
% #4 - smaller of the two tokens
% #5 - larger of the two tokens
\long\def\sort@output#1#2#3#4#5{%
        \ifsort@s{#3}
        {%
                \sortoutput{#4}%
                \sort#1{#2{#5}}%
        }% else
        {%
                \sort@begin#1{#2{#5}}{#4}#3\sort@begin
        }%
}

\def\sort@numlt#1#2#3{%
        \ifnumcomp{#1}<{#2}
        {#3{#1}{#2}}% else
        {#3{#2}{#1}}%
}

\def\sort@numgt#1#2#3{%
        \ifnumcomp{#1}>{#2}
        {#3{#1}{#2}}% else
        {#3{#2}{#1}}%
}

\def\sort@alpha#1#2#3{%
        \ifnumcomp{\pdfstrcmp{#1}{#2}}<{0}
        {#3{#1}{#2}}% else
        {#3{#2}{#1}}%
}

\long\def\fst#1#2{#1}
\long\def\snd#1#2{#2}
\long\def\sort@ref#1#2#3{%
    % Since #1 and #2 frequently contain newlines in their \snd part, and
    % \getrefnumber is not \long, we must take care to remove any newlines
    % *before* supplying an argument to \getrefnumber
    \edef\@leftref{\fst#1}%
    \edef\@rightref{\fst#2}%
    \ifnumcomp{\getrefnumber\@leftref}<{\getrefnumber\@rightref}%
    {#3{#1}{#2}}%
    {#3{#2}{#1}}%
}

\newcommand*\sortnumlt{\sort\sort@numlt}
\newcommand*\sortnumgt{\sort\sort@numgt}
\newcommand*\sortalpha{\sort\sort@alpha}
\newcommand\sortref{\sort\sort@ref}

% Change these to change out the sort outputs.
\newcommand\sortoutput[1]{%
    % As in the definition of \sort@ref, we must take care to remove
    % newlines before handing off to \ref
    \edef\@refname{\fst#1}%
    \item {\bf Case \ref\@refname:} \snd#1%
}
\newcommand\sortend\sortoutput

\makeatother

相关内容