![使用数组有意义的 & 符号来更改 foreach 循环中的列](https://linux22.com/image/376251/%E4%BD%BF%E7%94%A8%E6%95%B0%E7%BB%84%E6%9C%89%E6%84%8F%E4%B9%89%E7%9A%84%20%26%20%E7%AC%A6%E5%8F%B7%E6%9D%A5%E6%9B%B4%E6%94%B9%20foreach%20%E5%BE%AA%E7%8E%AF%E4%B8%AD%E7%9A%84%E5%88%97.png)
我希望循环遍历此代码:
\begin{tabular}{l*{8}c}
first column &
column a &
column b &
column c &
column d &
column e &
column f &
column g
\end{tabular}
但下面的代码无法编译:
\begin{tabular}{l*{8}c}
first column
\foreach \i in {a,b,c,d,e,f,g,h}{%
& column \i%
}
\end{tabular}
出现与我所写内容完全不同的错误:
! Extra }, or forgotten \endgroup.
<template> \unskip \hfil }
\hskip \tabcolsep \endtemplate
l.40 }
我一直希望这个帖子会有所帮助,但我不确定这个问题的这一部分是否最终得到了解答。
我怎样才能使这个循环工作?
答案1
xparse
使用and可以得到非常方便的语法expl3
。第二个参数代表#1
列表中各个项目的占位符。
\documentclass[a4paper]{article}
\usepackage[margin=1.5cm]{geometry}
\usepackage{booktabs}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\firstrow}{mmm}
{%#1 = first column
%#2 = format for the other columns
%#3 = comma separated list of values
\cs_gset_protected:Nn \__iagolito_temp:n { & #2 }
#1 \clist_map_function:nN { #3 } \__iagolito_temp:n
}
\ExplSyntaxOff
\begin{document}
\begin{tabular}{l*{8}c}
\firstrow{first column}{column #1}{a,b,c,d,e,f,g,h} \\
x & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 \\
\end{tabular}
\bigskip
\begin{tabular}{l*{8}c}
\toprule
\firstrow{first column}
{\begin{tabular}[t]{@{}c@{}}column\\ #1\end{tabular}}
{a,b,c,d,e,f,g,h} \\
\midrule
x & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 \\
\bottomrule
\end{tabular}
\end{document}
答案2
本质上,您无法使用以下方法使其工作\foreach
:每个表格单元格都是一个组,&
就像}{
结束一个组并开始一个新组一样,此时循环的内部状态将丢失。您要么需要一个不需要本地定义的不同循环系统,要么(就像您引用的问题的答案一样)只需使用表格行构建一个宏,然后在循环结束时执行该宏。
这显示了两种机制,请注意,在第二种机制中,循环数据在参数堆栈上进行管理,并且没有进行本地(或全局)定义,这使得在表“内部”执行循环更容易。
\documentclass[a4paper]{article}
\usepackage{tikz}
\addtolength\textwidth{2in}
\addtolength\oddsidemargin{-1in}
\begin{document}
\small\centering
\def\zz{first column}
\foreach \i in {a,b,c,d,e,f,g,h}{%
\xdef\zz{\zz & column \i}%
}
\begin{tabular}{l*{8}c}
\zz
\end{tabular}
\def\zzz#1{\zzza#1,\relax}
\def\zzza#1,#2\relax{&column #1\ifx\relax#2\relax\else\expandafter\zzza\fi#2\relax}
\begin{tabular}{l*{8}c}
first column \zzz{a,b,c,d,e,f,g,h}
\end{tabular}
\end{document}
答案3
以下是使用 token 和listofitems
:
基本上,它从逗号分隔的列表中创建一个标记列表,然后在您需要时调用该标记列表(使用\the\tabrows
):
\documentclass{article}
\usepackage{listofitems}
\makeatletter
\newtoks\tabrows
% Command for adding tokens to list
\newcommand\addrowraw[1]{\tabrows\expandafter{\the\tabrows#1}}
% Command that takes a comma separated list
% of items to be in the column of a row
% The second argument is what to do with the current column
% using the \thiscol command:
\newcommand\addrow[2]{
% Macro to contain the new list
\def\newrow{}
% Read argument as list for listofitems
\readlist\thecolumns{#1}
% Iterate and append the ampersand and the content of each column
\foreachitem\thiscol\in\thecolumns{
\edef\newrow{\unexpanded\expandafter{\newrow}}
}
% Remove first ampersand
\edef\newrow{\expandafter\@gobble\newrow}
% Just grouping it
\edef\newrow{{\newrow}}
\expandafter\addrowraw\newrow
% Add the \cr
\addrowraw{\\}
}
\begin{document}
% These should be _before_ the tabular environment
\addrow{a,b,c,d,e,f,g,h}{Col \thiscol, r1}
\addrow{i,j,k,l,m,n,o,p}{Col \thiscol, r2}
\begin{tabular}{l*{8}c}
\the\tabrows
\end{tabular}
\end{document}