![如何从文件加载表格,然后转置它并替换其标题(如果有)?](https://linux22.com/image/369416/%E5%A6%82%E4%BD%95%E4%BB%8E%E6%96%87%E4%BB%B6%E5%8A%A0%E8%BD%BD%E8%A1%A8%E6%A0%BC%EF%BC%8C%E7%84%B6%E5%90%8E%E8%BD%AC%E7%BD%AE%E5%AE%83%E5%B9%B6%E6%9B%BF%E6%8D%A2%E5%85%B6%E6%A0%87%E9%A2%98%EF%BC%88%E5%A6%82%E6%9E%9C%E6%9C%89%EF%BC%89%EF%BC%9F.png)
如果我有两种类型的数据库;第一种数据库具有带有行和列标题的原始数据,而第二种数据库只有原始数据。
我希望通过以下方式获得所需的输出:
1-(在第一种情况下)用我自己的标题替换行和列标题,或者(在第二种情况下)定义我自己的标题
2- 转置数据
\documentclass{article}
\usepackage{datatool,pgfplotstable,filecontents,booktabs}
% Case 1
\begin{filecontents*}{database1.csv}
,col1 , col2 , col3
row1 , 11 , 12 , 13
row2 , 21 , 22 , 23
\end{filecontents*}
% Case 2
\begin{filecontents*}{database2.csv}
11 , 12 , 13
21 , 22 , 23
\end{filecontents*}
\begin{document}
I would like the desired output for both databases to be
\begin{table}[h]
\centering
\caption{table caption}
\begin{tabular}{@{}lcc@{}}
\toprule
& First Column & Second Column\\
\midrule
First Row & 11 & 21 \\
\midrule
Second Row & 12 & 22 \\
\midrule
Third Row & 13 & 23 \\
\bottomrule
\end{tabular}
\end{table}
\end{document}
期望输出
答案1
该datatool
包将标题信息与实际数据分开存储。从这个意义上讲,它更像是结构化查询语言 (SQL) 数据库或数组数组,而不是电子表格应用程序。使用\DTLloaddb
或从 CSV 文件导入数据时\DTLloadrawdb
,将解析第一行以获取标题信息(除非noheader
使用该选项),其余行是数据。
标头信息提供列索引(从 1 开始)与可用作参考的标签之间的映射。每当使用接受标签作为列标识符的命令时,它都会在内部转换为相应的列索引。标头信息还包括列的标题(由\DTLdisplaydb
和使用\DTLdisplaylongdb
)和类型标识符(未知、字符串、整数、小数或货币)。
例如database1.csv
:
,col1 , col2 , col3
row1 , 11 , 12 , 13
row2 , 21 , 22 , 23
加载\DTLloaddb{database1}{database1.csv}
则第 1 列有一个空标签,第 2 列有标签col1
,第 3 列有标签col2
,第 4 列有标签col3
。行索引对应于实际数据的行(而不是 CSV 文件行号)。因此,第 1 行第 1 列的条目具有值row1
,第 1 行第 2 列的条目具有值11
(包括空格,因为\DTLloaddb
不修剪,所以您需要datatooltk
以改进 CSV 解析)。
因此,无需使用方便的高级用户命令(例如\DTLdisplaydb
或 )\DTLforeach
,就可以使用行和列索引来查找数据。
例如:
\documentclass{article}
\usepackage{datatool}
% Case 1
\begin{filecontents*}{database1.csv}
,col1 , col2 , col3
row1 , 11 , 12 , 13
row2 , 21 , 22 , 23
\end{filecontents*}
% Case 2
\begin{filecontents*}{database2.csv}
11 , 12 , 13
21 , 22 , 23
\end{filecontents*}
\DTLloaddb{database1}{database1.csv}
\DTLloaddb[noheader]{database2}{database2.csv}
\newcount\rowidx
\newcount\colidx
\newcommand{\rowthencolumn}[1]{%
\rowidx=0\relax
\loop % row loop
\advance\rowidx by 1\relax
{% column loop (needs scoping)
\colidx=0\relax
\loop
\advance\colidx by 1\relax
\ifnum\colidx>1 ,\space\fi
\DTLgetvalue{\thisvalue}{#1}{\rowidx}{\colidx}\thisvalue
\ifnum\colidx<\DTLcolumncount{#1}
\repeat
}%
\par
\ifnum\rowidx<\DTLrowcount{#1}
\repeat
}
\begin{document}
\section{database1}
Iterate row then column:
\rowthencolumn{database1}
\section{database2}
Iterate row then column:
\rowthencolumn{database2}
\end{document}
生成结果:
反转循环嵌套将首先迭代列,然后迭代行:
\documentclass{article}
\usepackage{datatool}
% Case 1
\begin{filecontents*}{database1.csv}
,col1 , col2 , col3
row1 , 11 , 12 , 13
row2 , 21 , 22 , 23
\end{filecontents*}
% Case 2
\begin{filecontents*}{database2.csv}
11 , 12 , 13
21 , 22 , 23
\end{filecontents*}
\DTLloaddb{database1}{database1.csv}
\DTLloaddb[noheader]{database2}{database2.csv}
\newcount\rowidx
\newcount\colidx
\newcommand{\columnthenrow}[1]{%
\colidx=0\relax
\loop % column loop
\advance\colidx by 1\relax
{% row loop (needs scoping)
\rowidx=0\relax
\loop
\advance\rowidx by 1\relax
\ifnum\rowidx>1 ,\space\fi
\DTLgetvalue{\thisvalue}{#1}{\rowidx}{\colidx}\thisvalue
\ifnum\rowidx<\DTLrowcount{#1}
\repeat
}%
\par
\ifnum\colidx<\DTLcolumncount{#1}
\repeat
}
\begin{document}
\section{database1}
Iterate column then row:
\columnthenrow{database1}
\section{database2}
Iterate column then row:
\columnthenrow{database2}
\end{document}
得出的结果为:
要跳过第一列,只需从下一个索引开始循环:
\documentclass{article}
\usepackage{datatool}
% Case 1
\begin{filecontents*}{database1.csv}
,col1 , col2 , col3
row1 , 11 , 12 , 13
row2 , 21 , 22 , 23
\end{filecontents*}
% Case 2
\begin{filecontents*}{database2.csv}
11 , 12 , 13
21 , 22 , 23
\end{filecontents*}
\DTLloaddb{database1}{database1.csv}
\DTLloaddb[noheader]{database2}{database2.csv}
\newcount\rowidx
\newcount\colidx
\newcommand{\columnthenrow}[2][0]{%
\colidx=#1\relax
\loop % column loop
\advance\colidx by 1\relax
{% row loop (needs scoping)
\rowidx=0\relax
\loop
\advance\rowidx by 1\relax
\ifnum\rowidx>1 ,\space\fi
\DTLgetvalue{\thisvalue}{#2}{\rowidx}{\colidx}\thisvalue
\ifnum\rowidx<\DTLrowcount{#2}
\repeat
}%
\par
\ifnum\colidx<\DTLcolumncount{#2}
\repeat
}
\begin{document}
\section{database1}
Iterate column then row:
\columnthenrow[1]{database1}
\section{database2}
Iterate column then row:
\columnthenrow{database2}
\end{document}
循环在每次迭代开始时增加索引,因此起点需要比实际值小一。以上产生:
列循环可以用 代替\dtlforeachkey
,它不仅提供当前迭代的列索引,还提供其他标题信息,其中包括标题标题:
\documentclass{article}
\usepackage{datatool}
% Case 1
\begin{filecontents*}{database1.csv}
,col1 , col2 , col3
row1 , 11 , 12 , 13
row2 , 21 , 22 , 23
\end{filecontents*}
% Case 2
\begin{filecontents*}{database2.csv}
11 , 12 , 13
21 , 22 , 23
\end{filecontents*}
\DTLloaddb[autokeys,headers={Column 1,Column 2,Column 3,Column 4}]
{database1}{database1.csv}
\DTLloaddb[noheader,headers={Column 1,Column 2,Column 3}]
{database2}{database2.csv}
\newcount\rowidx
\newcommand{\columnthenrow}[2][0]{%
\dtlforeachkey(\thiskey,\thiscol,\thistype,\thisheader)\in#2\do
{%
\ifnum\thiscol>#1\relax
% header title
\thisheader
% row loop
\rowidx=0\relax
\loop
\advance\rowidx by 1\relax
,\space
\DTLgetvalue{\thisvalue}{#2}{\rowidx}{\thiscol}\thisvalue
\ifnum\rowidx<\DTLrowcount{#2}
\repeat
\par
\fi
}%
}
\begin{document}
\section{database1}
Iterate column then row:
\columnthenrow[1]{database1}
\section{database2}
Iterate column then row:
\columnthenrow{database2}
\end{document}
得出的结果为:
您的自定义行标题需要在第一个循环之前添加:
\newcommand{\columnthenrow}[2][0]{%
Row 1, Row 2\par
\dtlforeachkey(\thiskey,\thiscol,\thistype,\thisheader)\in#2\do
{%
\ifnum\thiscol>#1\relax
% header title
\thisheader
% row loop
\rowidx=0\relax
\loop
\advance\rowidx by 1\relax
,\space
\DTLgetvalue{\thisvalue}{#2}{\rowidx}{\thiscol}\thisvalue
\ifnum\rowidx<\DTLrowcount{#2}
\repeat
\par
\fi
}%
}
循环并且tabular
混合效果不佳,因此要将其转换为良好的表格内容,最好先构建表格代码,然后使用它:
\documentclass{article}
\usepackage{booktabs}
\usepackage{datatool}
% Case 1
\begin{filecontents*}{database1.csv}
,col1 , col2 , col3
row1 , 11 , 12 , 13
row2 , 21 , 22 , 23
\end{filecontents*}
% Case 2
\begin{filecontents*}{database2.csv}
11 , 12 , 13
21 , 22 , 23
\end{filecontents*}
\DTLloaddb[autokeys,headers={Column 1,Column 2,Column 3,Column 4}]
{database1}{database1.csv}
\DTLloaddb[noheader,headers={Column 1,Column 2,Column 3}]
{database2}{database2.csv}
\newcount\rowidx
\newcommand{\columnthenrow}[2][0]{%
\def\tabularcontents{\begin{tabular}{lcc}\toprule&Row 1&Row2}%
\dtlforeachkey(\thiskey,\thiscol,\thistype,\thisheader)\in#2\do
{%
\ifnum\thiscol>#1\relax
% header title
\eappto\tabularcontents{%
\noexpand\\\noexpand\midrule\expandonce\thisheader}%
% row loop
\rowidx=0\relax
\loop
\advance\rowidx by 1\relax
\DTLgetvalue{\thisvalue}{#2}{\rowidx}{\thiscol}%
\eappto\tabularcontents{\noexpand&\expandonce\thisvalue}%
\ifnum\rowidx<\DTLrowcount{#2}
\repeat
\fi
}%
\appto\tabularcontents{\\\bottomrule\end{tabular}}%
\tabularcontents
}
\begin{document}
\section{database1}
\columnthenrow[1]{database1}
\section{database2}
\columnthenrow{database2}
\end{document}