Как заполнить динамически сгенерированную таблицу динамическим содержимым?

Как заполнить динамически сгенерированную таблицу динамическим содержимым?

как мне динамически сформировать таблицу, заполняя ее динамическими данными?

Пример: Допустим, у меня есть

\def\N{10}

и я хочу создать таблицу со \Nстолбцами, где верхняя ячейка каждого столбца содержит номер столбца, например

\begin{tabular}{|c|c|c|...|c|}
1 & 2 & 3 & ... & N
\end{tabular}

Это было самое близкое, что я нашел:

\newtoks\cols
\cols={}
\newcounter{i}
\setcounter{i}{1}
\loop
\cols=\expandafter{\the\cols \arabic{i}}
\ifnum\value{i}<\N
\cols=\expandafter{\the\cols &}
\stepcounter{i}
\repeat

\begin{tabular}{|*{\N}{c|}}
\the\cols
\end{tabular}

но из-за этого \expandafterу меня получается десять столбцов, каждый из которых содержит 10.

Есть ли способ выполнить что-то вроде частичного расширения? Я бы хотел расширить только , \arabic{i}но, конечно, не &.

решение1

Проблема в строке:

\cols=\expandafter{\the\cols \arabic{i}}

\colsявляется регистром токена, поэтому \arabic{i}не расширяется. Использование дополнительного \expandafterи вывода значения счетчика вместо \arabicпомогает:

\cols=\expandafter{\the\expandafter\cols\the\value{i}}

Полный пример:

\documentclass{article}

\newtoks\cols
\newcounter{i}
\newcount\N

\begin{document}
  \N=10
  \cols={}
  \setcounter{i}{1}
  \loop
    \cols=\expandafter{\the\expandafter\cols\the\value{i}}
  \ifnum\value{i}<\N
    \cols=\expandafter{\the\cols &}
    \stepcounter{i}
  \repeat
  \begin{tabular}{|*{\N}{c|}}
    \the\cols
  \end{tabular}
\end{document}

Результат

Расширяемая версия

В следующем примере используются e-TeX \numexpr. Необходимо следить за тем, чтобы \ifвложение было постоянным и &не должно быть видно слишком рано.

\documentclass{article}

\newcount\N

\makeatletter
\newcommand*{\Ncols}{%
  \Ncols@aux{1}%
}
\newcommand*{\Ncols@aux}[1]{%
  \ifnum#1>\N
    \expandafter\@gobble
  \else
    \expandafter\@firstofone
  \fi
  {% 
    \ifnum#1<2 \expandafter\@gobble\fi\Ncols@amp
    #1%
    \expandafter\Ncols@aux\expandafter{\the\numexpr(#1+1)}%
  }%
}
\newcommand*{\Ncols@amp}{&}
\makeatother

\begin{document}

\N=10
\begin{tabular}{|*{\N}{c|}}
\Ncols
\end{tabular}

\end{document}

Результат

решение2

Ответ Хайкообъяснил проблему с вашим кодом, как ее решить, а также как действовать в другом стиле, используя расширяемый целочисленный цикл (спасибо \numexpr).

Ответ А.Эллеттапредоставляет еще два решения с использованием pgfforи pgfkeys.

ответ DJPэто метод, использующий внешний инструмент, в данном случае Python codeуправляемый мощным Sagevia sagetex.

Все эти ответы в той или иной форме требуют некоторой дополнительной работы, например (для тех TeX) скрытие табуляции &в макросе, или выполнение глобальных определений с помощью \xdef, или подготовка регистра списка токенов, или использование различных видов TeXусловных операторов.

ThexintFor из пакетаxinttoolsявляется альтернативой (см.Как выполнить итерацию по списку, разделенному запятыми?), что избавляет от необходимости писать дополнительное кодирование:

\documentclass{article}
\usepackage{xinttools}
\newcommand{\N}{10}
\begin{document}
% \renewcommand{\N}{<nb of cols>}
\begin{tabular}{*{\N}c}
  \xintFor* #1 in {\xintSeq {1}{\N}}\do {\xintifForFirst{}{&}#1}\\
\end{tabular}
\end{document}

динамический табличный

Тест \xintifForFirst{YES}{N0}заключается в том, чтобы вставить табуляцию &только во вторую и следующую ячейки данной строки (здесь только одна строка). Макрос \xintSeqгенерирует арифметическую последовательность целых чисел (например {1}{2}{3}{4}). Макрос \xintFor* #1 inвыполняет итерации по своему аргументу (его не помеченный звездочкой кузен \xintForвыполняет итерации по списку, разделенному запятыми), позволяя #1каждому его элементу следовать один за другим.

Тот же код, что и выше, но с использованием счетчика LaTeX:

\documentclass{article}
\usepackage{xinttools}
\newcounter{N}
\begin{document}
\setcounter{N}{10}
\begin{tabular}{*{\value{N}}c}
  \xintFor* #1 in {\xintSeq {1}{\value{N}}}\do {\xintifForFirst{}{&}#1}\\
\end{tabular}
\end{document}

Вот более сложный пример (поскольку он использует два вложенных цикла), который строит таблицы умножения: \numexprиспользуется для умножения индекса строки на индекс столбца.

динамическая таблица 2

Вот код:

\documentclass{article}
\usepackage{xinttools}

\newcommand\MultTable [4]{% 
  % #1, #2 row indices
  % #3, #4 column indices: we need #4-#3+2 columns
  \begin{tabular}{*{\numexpr#4-#3+2\relax}c}
  \hline
  % headerline
  $\times$\xintFor* ##1 in {\xintSeq {#3}{#4}}\do{&\textbf{##1}}\\
  \hline
  % #2-#1+1 rows, ##1=dynamic index of each row, ##2 column index
  \xintFor* ##1 in {\xintSeq {#1}{#2}}\do
     {\textbf{##1}
      \xintFor* ##2 in {\xintSeq {#3}{#4}}\do{&\the\numexpr ##1*##2\relax}
      \\
     }
  \hline
  \end{tabular}%
% efficiency note: one could do \edef\columnindices {\xintSeq {#3}{#4}}
% before the tabular
% and use \columnindices rather \xintSeq {#3}{#4} to avoid it being
% re-computed for each row
}

\begin{document}
\begin{table}[!htbp]
  \centering
  \MultTable {1}{10}{1}{10}
  \caption{Multiplication table}
\end{table}
\begin{table}[!htbp]
  \centering
  \MultTable {123}{132}{91}{98}
  \caption{Multiplication table}
\end{table}
\end{document}

Поскольку мы использовали \xintFor*внутри определения пользовательской LaTeXкоманды, нам нужно было удвоить , #чтобы избежать путаницы между ##1циклом и тем, #1что , является первым параметром команды.

решение3

Если вы не против немного изучить Python,sagetex пакет может легко обрабатывать динамические таблицы; в конце концов, Python — мощный язык. Документация по sagetexздесьи в example.pdf они строят Треугольник Паскаля. Вот код для чего-то более близкого к тому, что вы просили; первая строка от 1 до N:

\documentclass{article}
\usepackage{sagetex}
\pagestyle{empty}
\begin{document}
\begin{sagesilent}
N = 5
M = 4
output = r"\begin{tabular}{"
for i in range(0,N):
    output += r"|c"
output += r"|}"
for j in range(0,M):
    for i in range(0,N-1):
        output += r"%d & "%((j+1)*(i+1))
    output += r"%d \\"%(N*(j+1))
output += r"\end{tabular}"
\end{sagesilent}
Here's the output:\\\\
\sagestr{output}
\end{document}

введите описание изображения здесь

С ограниченным объемом Python, который вам нужно изучить, я думаю, это, вероятно, проще, чем программировать в TeX. Вам нужно знать: циклы for не включают последнее значение, указанное в диапазоне, а r — для необработанной строки и позволяет избежать проблем, которые могут возникнуть из-за наличия в строке таких символов, как обратная косая черта. Наконец, %d — для вставки целых чисел, %f — для числа с плавающей точкой, а %s — для строки. Среда sagesilentнабирает фактический код, который затем вставляется через sagestr.

решение4

Это можно сделать разными способами, как уже предлагалось в комментариях и другом ответе. Вот два решения с использованием pgfforи pgfkeys.

Первое решение работает без использования ключей:

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

\makeatletter
\newcommand\aeDynamicTable{\ae@dynamicTable}
\def\ae@dynamicTable[#1]#2{%%
  \let\ae@table@content\relax%%
  \def\ae@new@column{&}
  \def\ae@row{0}%%
  \foreach \x in {1,...,#2}
    {%%
      \xdef\ae@row{\number\numexpr\ae@row+1\relax}%%
      \ifx\relax\ae@table@content
        \xdef\ae@table@content{\noexpand\@arabic{\x}}%
      \else
        \xdef\ae@table@content{\expandonce{\ae@table@content} \noexpand\@arabic{\x}}%%
      \fi
      \ifnum\ae@row=#1\relax
        \xdef\ae@row{0}%%
        \def\ae@new@line{\\}%%
        \def\ae@new@column{}%%
      \else
        \def\ae@new@line{}%%
        \def\ae@new@column{&}%%
      \fi
      \ifnum\x=#2\relax
        \def\ae@new@line{}%%
        \def\ae@new@column{}%%
      \fi
      \xdef\ae@table@content{\expandonce{\ae@table@content} \expandonce{\ae@new@column} \expandonce{\ae@new@line}}%
    }%%
    \begin{tabular}{|*{#1}{c|}}
      \ae@table@content 
    \end{tabular}%%
  }

\makeatother

\begin{document}

\aeDynamicTable[3]{5}

\aeDynamicTable[10]{35}

\end{document}

Во втором примере та же задача выполняется с использованием ключей:

\documentclass{article}
\usepackage{pgffor}
\usepackage{pgfkeys}
\usepackage{etoolbox}

\makeatletter
\def\ae@col@limit{}
\def\ae@max@cells{}
\pgfkeys{/ae/dynamic/table/.cd,
  cols/.store in=\ae@col@limit,
  cells/.store in=\ae@max@cells,
}

\newcommand\aeDynamicTable{\ae@dynamicTable}
\def\ae@dynamicTable#1{%%
  \pgfkeys{/ae/dynamic/table/.cd,#1}%% 
  \let\ae@table@content\relax%%
  \def\ae@new@column{&}
  \def\ae@col{0}%%
  \foreach \x in {1,...,\ae@max@cells}
    {%%
      \xdef\ae@col{\number\numexpr\ae@col+1\relax}%%
      \ifx\relax\ae@table@content
        \xdef\ae@table@content{\noexpand\@arabic{\x}}%
      \else
        \xdef\ae@table@content{\expandonce{\ae@table@content} \noexpand\@arabic{\x}}%%
      \fi
      \ifnum\ae@col=\ae@col@limit\relax
        \xdef\ae@col{0}%%
        \def\ae@new@line{\\}%%
        \def\ae@new@column{}%%
      \else
        \def\ae@new@line{}%%
        \def\ae@new@column{&}%%
      \fi
      \ifnum\x=\ae@max@cells\relax
        \def\ae@new@line{}%%
        \def\ae@new@column{}%%
      \fi
      \xdef\ae@table@content{\expandonce{\ae@table@content} \expandonce{\ae@new@column} \expandonce{\ae@new@line}}%
    }%%
    \begin{tabular}{|*{\ae@col@limit}{c|}}
      \ae@table@content 
    \end{tabular}%%
  }

\makeatother

\begin{document}

\aeDynamicTable{cols=3,cells=5}

\aeDynamicTable{cols=10,cells=35}

\end{document}

В любом случае результирующие таблицы будут следующими:

введите описание изображения здесь

Связанный контент