假设我有一张包含两列的表格。我该如何根据第一列对行进行排序?在 latex 中可以吗?如果我在另一个应用程序(如 MS Excel)中执行此操作,我可以将工作表中的数据导入表格吗?
如果您能建议我一种处理这种排序的方法,我会非常高兴,越简单越好!顺便说一句,我看了按字母数字列表排序根本就没得到它!
答案1
我毫不怀疑这datatool
是可行的方法。但是,可以使用我对排序问题的回答中的代码来执行此操作。
您需要定义一个仅比较第一列的新比较器。此特定实现需要具有行顶级扩展的东西。例如,您可以为每一行定义一个宏。
\def\rowi {C & foo & qwer \\}
\def\rowii {A & bar & asdf \\}
\def\rowiii{B & baz & zxcv \\}
目标是能够编写以下内容来获取排序后的行。
\begin{tabular}{lll}
\toprule
Letters & Metasyntatic variables & Gibberish\\
\midrule
\sortfirstcol{\rowi\rowii\rowiii}
\bottomrule
\end{tabular}
具体来说,\sortfirstcol{\rowi\rowii\rowiii}
应该扩展为已排序的行。与 一样\sortalpha
,\sortfirstcol
只是一个简单的宏,\sort
以比较器\sort@firstcol
作为其第一个参数进行扩展。
\newcommand*\sortfirstcol{\sort\sort@firstcol}
比较器并不复杂,但它确实需要提取每个参数的第一列。为此,我们使用辅助宏。为了与原始答案的精神保持一致,此版本是可扩展的。
\def\sort@firstcol#1#2{%
\expandafter\expandafter\expandafter
\sort@fc@helper\expandafter#1#2#1#2%
}
\def\sort@fc@helper#1\\#3\\#5#6#7{%
\ifnumcomp{\pdfstrcmp{#1}{#3}}<{0}
{#7{#5}{#6}}% else
{#7{#6}{#5}}%
}
s\expandafter
将一次性扩展前两个参数。例如,如果比较器被“调用”为\sort@firstcol{\rowi}{\rowii}{...}
,则它将扩展为
\sort@fc@helper C & foo & qwer \\A & bar & asdf \\\rowi\rowii{...}
因此#1
将是标记“C”,#3
将是“A”,#5
将是\rowi
,#6
将是\rowii
,最后#7
将是{...}
传递给比较器的延续。
从这里开始,它与 相同\sort@alpha
:它比较#1
和#3
,并将#5
和传递#6
到延续。
最后,由于行的表示,\sortend
和\sortoutput
宏应该设置为仅扩展到它们的参数:
\newcommand*\sortoutput[1]{#1}
\newcommand*\sortend[1]{#1}
以下是使用上述代码和上一个答案中的代码的完整示例。
\documentclass{article}
\usepackage{etoolbox}
\usepackage{booktabs}
\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}}%
}
\def\sort@firstcol#1#2{%
\expandafter\expandafter\expandafter
\sort@fc@helper\expandafter#1#2#1#2%
}
\def\sort@fc@helper#1\\#3\\#5#6#7{%
\ifnumcomp{\pdfstrcmp{#1}{#3}}<{0}
{#7{#5}{#6}}% else
{#7{#6}{#5}}%
}
\newcommand*\sortnumlt{\sort\sort@numlt}
\newcommand*\sortnumgt{\sort\sort@numgt}
\newcommand*\sortalpha{\sort\sort@alpha}
\newcommand*\sortfirstcol{\sort\sort@firstcol}
\makeatother
% Change these to change out the sort outputs.
\newcommand*\sortoutput[1]{#1}
\newcommand*\sortend[1]{#1}
\begin{document}
\def\rowi {C & foo & qwer \\}
\def\rowii {A & bar & asdf \\}
\def\rowiii{B & baz & zxcv \\}
\begin{tabular}{lll}
\toprule
Letters & Metasyntatic variables & Gibberish\\
\midrule
\sortfirstcol{\rowi\rowii\rowiii}
\bottomrule
\end{tabular}
\end{document}
最后,我应该指出,这种表示(即,将行作为宏)不是必需的。由于\sort
处理其参数的方式,可以轻松编写一个比较器,允许编写以下内容。
\sortfirstcol{%
{C & foo & qwer}%
{A & bar & asdf}%
{B & baz & zxcv}%
}
\def\sortoutput#1{#1\\}
\def\sortend#1{#1\\}
也许我应该这么做。比较器会稍微简单一些。
此外,在实施过程中,第一列开头或结尾的空格很重要。人们可能也会处理这个问题。
答案2
这datatool
该包有很多函数可以对数据进行排序和分析。
答案3
有许多很好的技术可以将 Excel 或其他电子表格数据传输到 latex 源中。请参阅此答案这里。如果您在 Mac 上使用 TeXShop,还有一个内置的“粘贴电子表格单元格”宏可以完成这个操作。