使用 LaTeX 压缩数字列表

使用 LaTeX 压缩数字列表

这有点不寻常。但是有人用过 LaTeX 来压缩数字列表吗?

我想到的最接近的例子是使用引用包。因此,如果我写\cite{key1, key2, key3, key4, key5},我们会得到类似 1-3、7、9 的内容。

所考虑的情况几乎相似,只是数字是实数或扩展为实数,而不是引用键。因此,如果我写\compactthis{1,2,3,4,5,9,8,7, 11},我将得到 1-5、7-9、11。

有没有快速实现此目的的方法?从头开始编写宏需要花费时间,而我现在无法承受。

(我知道编程语言更适合这种情况,但我目前的情况要求使用 LaTeX。)

答案1

编辑以对输入流进行排序使用冒泡排序(如果需要,\bubblesort可以独立于\compactthis宏使用宏)。

必须\listterminator设置为任何已知不在列表中的数值(例如,足够大、负数、零等),当前设置为9999。如图所示(在代码中和在 MWE 中演示),如果对于相邻的限制条目,优先于 ,\adjtie则可以将宏设置为。 --1--21, 2

无需任何包裹。

\documentclass{article}
%
% THIS CODE CAN \bubblesort A NUMBERED LIST AND THEN \compactthis LIST IN THE MANNER
% OF 1-3, 7, 11-13
%
\def\listterminator{9999}% SET TO *ANY* VALUE KNOWN NOT TO BE IN LIST (POSITIVE OR NEGATIVE)
\def\adjtie{, }
%\def\adjtie{--}% OPTIONAL IF 1--2 preferred over 1, 2
\newcommand\compactthis[1]{%
  \bubblesort{#1}%
  \expandafter\begincompaction\sortedlist,\listterminator,\relax%
}
\def\begincompaction#1,#2\relax{%
  \def\startlist{#1}%
  \def\currentendlist{#1}%
  \findendlist#2\relax%
}
\def\findendlist#1,#2\relax{%
  \ifnum\numexpr\currentendlist+1\relax=#1\relax%
    \def\currentendlist{#1}%
    \findendlist#2\relax%
  \else%
    \ifnum\startlist=\currentendlist\relax%
      \ignorespaces\startlist\unskip%
    \else%
      \ifnum\numexpr\startlist+1\relax=\currentendlist\relax%
        \ignorespaces\startlist\unskip\adjtie\ignorespaces\currentendlist\unskip%
      \else%
        \ignorespaces\startlist\unskip--\ignorespaces\currentendlist\unskip%
      \fi%
    \fi%
    \ifnum#1=\listterminator\else,\ \begincompaction#1,#2\relax\fi%
  \fi%
}
\newcommand\bubblesort[1]{\def\sortedlist{}\sortlist#1,\listterminator,\relax}
\def\sortlist#1,#2,#3\relax{%
  \ifnum#2=\listterminator\relax%
    \edef\sortedlist{\sortedlist#1}%
  \else
    \ifnum#1<#2\relax%
      \edef\sortedlist{\sortedlist#1,}%
      \sortlist#2,#3\relax%
    \else%
      \let\tmp\sortedlist%
      \def\sortedlist{}%
      \expandafter\sortlist\tmp#2,#1,#3\relax%
    \fi%
  \fi%
}
\begin{document}
Bubble Sort Demonstration: 
\bubblesort{1,2,11, 7, 4, 3}\sortedlist\par
\compactthis{1,2,3,4,5,7,8,9, 11}\par
\compactthis{1,2, 12 ,13 ,18, 20} (single member)\par
\compactthis{1,2, 12,13,18, 19, 20} (range at end)\par
\def\adjtie{--}\compactthis{1,2, 12,13,18, 19, 20} (\verb|\adjtie| set to {--})\par
\compactthis{1,2,11, 7, 4, 3, 12, 14, 13} (unsorted input)
\end{document}

在此处输入图片描述

答案2

以下是您需要的大部分内容,其中输入为黑色,输出为红色:

在此处输入图片描述

笔记:

代码:

\documentclass{article}
\usepackage{pgffor}
\usepackage{xstring}
\usepackage{etoolbox}
\usepackage{xcolor}

\newtoggle{StartedRange}
\newcommand{\LastNumber}{}%
\newcommand{\LastRangeStart}{}%
\newcommand*{\compactthis}[1]{%
    \edef\ExpandedParam{#1}% <-- Apply sorting here
    \ExpandedParam:
    \begingroup\color{red}%
    \togglefalse{StartedRange}%
    \foreach \x in \ExpandedParam {%
        \iftoggle{StartedRange}{%
            \pgfmathtruncatemacro\ExpectedNextNumber{\LastNumber+1}%
            \IfEq{\ExpectedNextNumber}{\x}{%
                %% Continue this range
            }{%
                \IfEq{\LastRangeStart}{\LastNumber}{%
                    %% Was a single member
                }{%
                    --\LastNumber% Close last range
                }%
                ,\, \x%        and start a new range
                \xdef\LastRangeStart{\x}%
            }%
       }{%
            \x% initial range
            \xdef\LastRangeStart{\x}%
            \global\toggletrue{StartedRange}%
        }%
        \xdef\LastNumber{\x}%
    }%
    %  Process any ranges at end of list:
    \IfEq{\LastRangeStart}{\LastNumber}{%
        %% Was a single member
    }{%
        --\LastNumber% Close last range
    }%
    \endgroup%
}%

\begin{document}
\compactthis{1,2,3,4,5,7,8,9, 11}

\compactthis{1,2, 12,13,18, 20}% Single member

\compactthis{1,2, 12,13,18, 19, 20}% range at end

\end{document}

答案3

这是一个 LuaLaTeX 解决方案。由于 Lua 具有易于使用的排序函数 ( table.sort),因此它还会对输入列表进行排序。可能有一些方法可以使 Lua 代码更简洁,但对于熟悉命令式编程语言的人来说,它应该很容易理解。

\documentclass{article}
\usepackage{luacode}

\begin{luacode*}
function print_range(range_min, range_max)
  if range_min == range_max then
    tex.sprint(tostring(range_min))
  else
    tex.sprint(tostring(range_min) .. "--" .. tostring(range_max))
  end
end
function compactthis(...)
  local numbers = {...}
  table.sort(numbers)
  local range_started = false
  local range_min = 0
  local range_max = 0
  for i = 1, #numbers do
    if range_started then
      if numbers[i] <= range_max + 1 then
        range_max = numbers[i]
      else
        print_range(range_min, range_max)
        range_started = false
      end
    end
    if not range_started then
      if i ~= 1 then
        tex.sprint(", ")
      end
      range_started = true
      range_min = numbers[i]
      range_max = numbers[i]
    end
  end
  if range_started then
    print_range(range_min, range_max)
  end
end
\end{luacode*}
\newcommand\compactthis[1]{\luaexec{compactthis(#1)}}

\begin{document}
\compactthis{1,2,3,4,5,9,8,7,11}
\end{document}

相关内容