# Order list of names with Lua

I want to define a command using \directlua that looks something like:

\sort{c, b, a}


and outputs a, b, c to the document.

In ConTeXt you do not have to reinvent the wheel.

\def\sort#1{%
\ctxlua{
context(
table.concat(
table.sorted(
utilities.parsers.settings_to_array([[#1]]) ) , ", " ) )
}}

\starttext

\sort{c, b, a}

\stoptext


You can also use it with LaTeX by including the appropriate Lua headers from ConTeXt.

\documentclass{article}

\directlua{
dofile(kpse.find_file("l-lpeg.lua"))
dofile(kpse.find_file("util-sto.lua"))
dofile(kpse.find_file("util-prs.lua"))
}

\def\sort#1{%
\directlua{\unexpanded{
tex.sprint(
table.concat(
table.sorted(
utilities.parsers.settings_to_array([[#1]]) ) , ", " ) )
}}}

\begin{document}

\sort{c, b, a}

\end{document}


The output is similar.

To omit empty entries (empty string) one has to write one additional helper function, which I could not find in ConTeXt. However, multiple empty entries side by side seem to confuse at least one of the functions, i.e. \sort{,,,,a} will produce spurious commas.

\documentclass{article}

\directlua{
dofile(kpse.find_file("l-lpeg.lua"))
dofile(kpse.find_file("l-string.lua"))
dofile(kpse.find_file("util-sto.lua"))
dofile(kpse.find_file("util-prs.lua"))

function table.strip_empty(tab)
for k, v in pairs(tab) do
if ( string.strip(v) == "" ) then
table.remove(tab, k)
end
end
return tab
end
}

\def\sort#1{%
\directlua{\unexpanded{
tex.sprint(
table.concat(
table.sorted(
table.strip_empty(
utilities.parsers.settings_to_array([[#1]]) ) ) , ", " ) )
}}}

\begin{document}

\sort{, d, , f, c, b, a, }

\end{document}

• +1. Is there a way to modify the routines to automatically delete any leading commas (say, because the command was \sort{c, ,b, a,})?
– Mico
Mar 13, 2017 at 13:10
• @Mico See updated answer. Unfortunately, I could not find a remove function in ConTeXt. Mar 13, 2017 at 16:05

Here's a possible solution. The main Lua function, called dojob, converts the input string into a Lua table (via a call to an auxiliary Lua function called string_to_table), performs a simple sort, and outputs the table elements as a string, with the elements separated by "," ("comma&space"). Any leading or trailing whitespace characters and commas are discarded automtically.

The Lua function dojob may be accessed from within the body of a LaTeX document via the LaTeX macro called \sort.

Aside: Much of the Lua code in the string_to_table function was obtained from this site. (Look for the header "Method: Using only string.gsub" for more details on how the code works.) For good measure, I added a routine that removes leading and trailing whitespace from the table entries.

The sorting routine is simple. I trust your comma-separated list isn't so long as to require a more efficient sorting algorithm (e.g., QuickSort) in order to avoid getting bogged down.

% !TeX program = lualatex
\documentclass{article}
%% Lua-side code
\usepackage{luacode}
\begin{luacode}

function string_to_table (str)
sep = ","
fields = {}
str:gsub( "([^"..sep.."]*)" .. sep ,
function(c)
c = string.gsub ( c, "^%s*(.-)%s*$", "%1" ) table.insert (fields, c) end) return fields end function dojob ( s ) -- append "," (if needed) to end of string if (string.sub(s,-1) == ",") then else s = s.."," end -- convert string to table t = string_to_table ( s , "," ) -- sort the table entries table.sort ( t , function(a,b) return a<b end) -- convert table to string, with items separated by commas s = table.concat ( t, ", " ) -- remove any leading whitespace and comma characters, output the string tex.sprint ( (string.gsub( s, "^[,%s]*(.*)$", "%1" ) ) )
end

\end{luacode}

%% TeX-side code
\newcommand\sort[1]{\directlua{dojob(\luastring{#1})}}

\begin{document}
\sort{c, b, a}

\sort{Carla , Eric , Anna Michelle, Brenda  , Daniel}

\sort{Eric,Carla,Brenda,Anna Michelle,Daniel,,}

\sort{aaa,15}
\end{document}