如何从文件加载表格,然后转置它并替换其标题(如果有)?

如何从文件加载表格,然后转置它并替换其标题(如果有)?

如果我有两种类型的数据库;第一种数据库具有带有行和列标题的原始数据,而第二种数据库只有原始数据。

我希望通过以下方式获得所需的输出:

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}

生成结果:

1 数据库 1 先迭代行然后迭代列:行 1 、 11 、 12 、 13 行 2 、 21 、 22 、 23 2 数据库 2 先迭代行然后迭代列:11 、 12 、 13 21 、 22 、 23

反转循环嵌套将首先迭代列,然后迭代行:

\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}

得出的结果为:

1 数据库 1 先迭代列然后迭代行:行 1、行 2 11、21 12、22 13、23 2 数据库 2 先迭代列然后迭代行:11、21 12、22 13、23

要跳过第一列,只需从下一个索引开始循环:

\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}

循环在每次迭代开始时增加索引,因此起点需要比实际值小一。以上产生:

1 数据库 1 先迭代列然后迭代行:11、21 12、22 13、23 2 数据库 2 先迭代列然后迭代行:11、21 12、22 13、23

列循环可以用 代替\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}

得出的结果为:

1 数据库 1 先迭代列然后迭代行:第 2 列、11、21 第 3 列、12、22 第 4 列、13、23 2 数据库 2 先迭代列然后迭代行:第 1 列、11、21 第 2 列、12、22 第 3 列、13、23

您的自定义行标题需要在第一个循环之前添加:

\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}

列表内容图像

相关内容