標籤:

在 LaTeX 中怎麼排序數字?

需要排序一些簡單的數字,在 LaTeX 中應該怎麼做?


可以用 LaTeX3 項目的 l3sort 宏包 [1],具體用法就請自行查看它的手冊吧。

為了提高性能,l3sort 先將待排序的項目逐個保存到 oks 寄存器中(時間複雜度為 O(n))。因此對排序的項目數量有限制,LuaTeX 最多只能有 49152 項,其他 eTeX 引擎是 24576 項。

l3sort 採用的是自底向上的歸併排序演算法 [2],時間複雜度為 O(nlog n),但效率遠比不上其他編程語言。比如在我這裡,下面的簡單例子,排序 22000 個數字,需要 0.8 秒左右:

% !TeX program = pdflatex

RequirePackage{l3benchmark}
RequirePackage{l3sort}

ExplSyntaxOn

%% 生成 22000 個數字。
l_set:Nx l_tmpa_tl
{ prg_replicate:nn { 2000 } { 13641344123 } }

enchmark:n
{
l_sort:Nn l_tmpa_tl
{
if_int_compare:w #1 &> #2 exp_stop_f:
exp_after:wN sort_reversed:
else:
exp_after:wN sort_ordered:
fi:
}
}

ex_end:D

但我覺得能用 TeX 做到這樣子,已經相當不錯了。

--------------------------------------------------

我在 LuaTeX 中用 Lua 實現的歸併排序對比了一下。首先是 Lua 腳本 mergesort.lua:

local function merge (a, b)
local r = {}
local i, j = 1, 1
local m, n = #a, #b
for k = 1, m + n do
if j &> n or (i &<= m and a[i] &<= b[j]) then r[k] = a[i] i = i + 1 else r[k] = b[j] j = j + 1 end end return r end local function split (a) local a1, a2 = {}, {} local n = #a local mid = math.floor(n / 2) for i = 1, mid do a1[i] = a[i] end for i = 1, n - mid do a2[i] = a[i + mid] end return a1, a2 end function merge_sort (a) if #a &> 1 then
local a1, a2 = split(a)
return merge(merge_sort(a1), merge_sort(a2))
else
return a
end
end

然後是測試用的 TeX 腳本:

% !TeX program = lualatex

RequirePackage{l3benchmark}
RequirePackage{l3sort}

% 生成 49152 個隨機數字。
directlua
{
rand_int_array = {}
math.randomseed(os.time())
for i = 1, 49152 do
rand_int_array[i] = math.random(1000000)
end
}

ExplSyntaxOn

l_const:Nx c_test_clist
{ directlua { tex.sprint(table.concat(rand_int_array, ",")) } }

clist_set_eq:NN l_tmpa_clist c_test_clist
enchmark:n
{
clist_sort:Nn l_tmpa_clist
{
if_int_compare:w #1 &> #2 exp_stop_f:
exp_after:wN sort_reversed:
else:
exp_after:wN sort_ordered:
fi:
}
}

directlua { dofile("mergesort.lua") }
enchmark:n
{
l_set:Nx l_tmpa_clist
{
directlua
{
local ~ a = string.explode("c_test_clist", ",")
tex.sprint(table.concat(merge_sort(a), ","))
}
}
}

ex_end:D

用 lualatex 運行上述腳本,我這裡輸出為

3.025009155273437 seconds
0.486248016357422 seconds

TeX 的實現比 Lua 慢了大約一個數量級。

[1]: CTAN: Package l3experimental

[2]: Merge sort


直接的工具,有 arraysort 宏包。專門用來對 arrayjobx 風格的數組排序。例子:

documentclass{article}
usepackage[comparenum]{arraysort}

egin{document}

ewarray{Arr}

eadarray{Arr}{23571468910}
% 排序前
Arr(1), Arr(2), Arr(3), Arr(4), Arr(5), Arr(6), Arr(7), Arr(8), Arr(9), Arr(10)

sortArray[arraysortcomparenum]{10}{Arr}
% 排序後
Arr(1), Arr(2), Arr(3), Arr(4), Arr(5), Arr(6), Arr(7), Arr(8), Arr(9), Arr(10)

end{document}

還有 LaTeX3 的實驗性宏包 l3sort,對逗號列表或 LaTeX3 風格的 sequence 排序。例子:

documentclass{article}
usepackage{l3sort}

egin{document}

ExplSyntaxOn

clist_set:Nn l_foo_clist { 2,3,5,7,1,4,6,8,9,10 }

% 排序前
l_foo_clistpar

clist_sort:Nn l_foo_clist {
int_compare:nNnTF {#1}&<{#2} {sort_ordered:} {sort_reversed:} } % 排序後 l_foo_clist ExplSyntaxOff end{document}

TeX.sx 上有其他一些做法,見

programming - How to sort an alphanumeric list

裡面 TH. 給出了一個可完全展開的插入排序,也比較容易理解。


推薦閱讀:

自學 LaTeX 可以讀什麼書入門?
如何排出精美的中文論文?
用 LaTeX 做幻燈片比用 PowerPoint 和 Keynote 做更方便、更美觀嗎?
中文寫論文行間公式要不要加空格?

TAG:編程 | LaTeX |