使用 pgfplotstable 有选择地将一列写入适当的行?

使用 pgfplotstable 有选择地将一列写入适当的行?

描述: 我有一个名为namespgf.csv

Reg.No.,Name
5501,Kathirvelu A
5502,Gugan K
5503,Kalaitchelvi S
5504,Suresh S
5505,Mahesh K

另一个名为markspgf.csv

number,marks
5501,67
5502,25
5503,62
5505,95

请注意注册号码 5504 不在markspgf.csv

现在我尝试将该marks列复制到文件中namespgf.csv并排版如下的表格(这是我想要的):

Reg.No.     Name                 marks
5501        Kathirvelu A         67
5502        Gugan K              25
5503        Kalaitchelvi S       62
5505        Mahesh K             95

这里,考生的注册号5504在“markspgf.csv”中没有分数。我想从上面的结果表中省略与该号码相对应的条目。但这是我尝试得到的结果:

在此处输入图片描述

以下是生成表格的代码(MWE):

\documentclass{article}
\usepackage{pgfplotstable}
\usepackage{filecontents}
%
\begin{filecontents}{namespgf.csv}
Reg.No.,Name
5501,Kathirvelu A
5502,Gugan K
5503,Kalaitchelvi S
5504,Suresh S
5505,Mahesh K
\end{filecontents}
%
\begin{filecontents}{markspgf.csv}
number,marks
5501,67
5502,25
5503,62
5505,95
\end{filecontents}
\begin{document}
%=============================================================================
\pgfplotstableread[col sep=comma]{namespgf.csv}\namespgf
\pgfplotstableread[col sep=comma,verb string type]{markspgf.csv}\markspgf
%
\pgfkeys{/pgfplots/table/verb string type}
% ----------------------------------------------------------------------%
\pgfplotstablecreatecol[copy column from table={\markspgf}{[index] 1},skip first n=1] {marks} {\namespgf}
%
{\centering
 \pgfplotstabletypeset[columns={Reg.No.,Name,marks}
 ]{\namespgf}
}
%
\end{document}

问题:

如何省略与注册号 5504 对应的条目,并在注册号 5505 前面加上正确的标记?(如何获取我上面解释的表格)?

请注意我想要一个使用的解决方案pgfplotstable。这背后的主要原因是我正在处理的数据量。对于如此大量的数据,datatool编译需要花费数年时间,有时 pdflatex 会耗尽内存。但pgfplotstable它速度快,内存效率高。

答案1

编辑请参阅编辑历史以了解不完整的答案。


我所做的是遍历Reg.No.条目并尝试查看表number的列中是否有匹配项\markspgf。如果有,那么我们marks在创建新列时使用该行的值,否则我们将输入N/A.(如果不需要,可以跳过此步骤)。然后,我们记录计数器值,因为\pgfplotstablerow变量现在不可用,因此我们会跟踪未能匹配的行并增加计数器。

当数字用完后,我们将在新表中使用这个新列,并再次检查每一行是否要使用此行。 如果行号与列表中的第一个数字匹配,我们将触发 if 条件,否则什么也不会\pgfplotsuserowfalse发生,并且行被排版。

\documentclass{article}
\usepackage{pgfplotstable,xstring}
\usepackage{filecontents,etoolbox}
%
\begin{filecontents}{namespgf.csv}
Reg.No.,Name,Place
5501,Kathirvelu A,re
5502,Gugan K,rt
5503,Kalaitchelvi S,uy
5504,Suresh S,itr
5505,Mahesh K,utyehd
5506,Balini N,utyehd
5507,Kumar H,utyehd
5508,Khalate A,utyehd
5509,me,hgte
5510,you,there
5511,them,here
5512,who,where 
\end{filecontents}
%
\begin{filecontents}{markspgf.csv}
number,marks
5501,67
5502,25
5503,62
5505,95
5507,100
5512,45
\end{filecontents}
\def\marksuccess{}
\def\mypopulatedlist{}
\newcounter{myrowcount}
\setcounter{myrowcount}{0}


\begin{document}
%=============================================================================
\pgfplotstableread[col sep=comma]{namespgf.csv}\namespgf
\pgfplotstableread[col sep=comma,verb string type]{markspgf.csv}\markspgf
%
\pgfkeys{/pgfplots/table/verb string type}
% ----------------------------------------------------------------------%
\pgfplotstablecreatecol[
create col/assign/.code={%
\let\marksuccess\relax
    \pgfplotstableforeachcolumnelement{number}\of\markspgf\as\cellb{%
        \IfStrEq{\thisrow{Reg.No.}}{\cellb}{%True
            \pgfplotstablegetelem{\pgfplotstablerow}{marks}\of\markspgf
            \edef\myretval{\pgfplotsretval}
            \def\marksuccess{1}
             %\breakforeach %This would have saved some time if it was available
        }
        {}%False
    }
    \if\marksuccess\relax
    \def\myretval{N/A}%
    \xappto\mypopulatedlist{\arabic{myrowcount},}
    \else
    \fi
    \stepcounter{myrowcount}
    \pgfkeyslet{/pgfplots/table/create col/next content}\myretval
}]{Marks}\namespgf


\pgfplotstabletypeset[
column type=l,
columns={Reg.No.,Name,Marks},
row predicate/.code={%
\StrBefore{\mypopulatedlist}{,}[\mynextrow] %Look at the first number before the comma on the list
\IfStrEq{#1}{\mynextrow}{%If the current row is equal to that number
\StrLen{\mynextrow}[\numberlength]%Get the length of the number
\StrGobbleLeft{\mypopulatedlist}{\number\numexpr\numberlength+1\relax}[\mytemplist]%Delete this number and the next comma from the list
\edef\mypopulatedlist{\mytemplist}%Overwrite the old list with the new
\pgfplotstableuserowfalse% Tell pgfplots to omit this row
}{}
}
]\namespgf

\end{document}

在此处输入图片描述

答案2

这是一个使用的解决方案包裹datatool

在此处输入图片描述

笔记:

  • 在下面的 MWE 中,我使用了这样filecontents*标题filecontents就不会添加到数据文件中。

代码:

\documentclass{article}
\usepackage{datatool}
\usepackage{xstring}
\usepackage{filecontents}

\begin{filecontents*}{namespgf.csv}
Reg.No.,Name
5501,Kathirvelu A
5502,Gugan K
5503,Kalaitchelvi S
5504,Suresh S
5505,Mahesh K
\end{filecontents*}
%
\begin{filecontents*}{markspgf.csv}
number,marks
5501,67
5502,25
5503,62
5505,95
\end{filecontents*}

%------- Useful for debuging ---------------
\newcommand{\PrintNamesDTLTable}[1]{% #1 = names database
    \begin{tabular}{c c}%
        Reg No & Name \\\hline%
    \DTLforeach{#1}{%
        \RegNo=Reg.No.,%
        \Name=Name%
        }{%
        \RegNo & \Name\\%
    }%
    \end{tabular}%
}%

\newcommand{\PrintMarksDTLTable}[1]{% #1 = marks database
    \begin{tabular}{c c}%
        Number & Marks \\\hline%
    \DTLforeach{#1}{%
        \Number=number,%
        \Marks=marks%
        }{%
        \Number & \Marks\\%
    }%
    \end{tabular}%
}%
%-------------------------------------------

\newcommand*{\PrintIfRegNumberIsInMarks}[3]{%
    % #1 = reg number
    % #2 = name
    % #3 = marks db
    %
    \DTLforeach{#3}{\Number=number, \Marks=marks}{%
        \IfEq{#1}{\Number}{% Found member
            #1 & #2 & \Marks \\%
            \dtlbreak% Done, break out of loop
        }{% Haven't found it yet, so keep looking....
        }%
    }%
}%

\newcommand{\PrintNamesWithMarksDTLTable}[2]{%
    % #1 = names database
    % #2 = marks database
    \begin{tabular}{c c c}%
        Reg No & Name & Marks\\\hline%
        \DTLforeach{#1}{%
            \RegNo=Reg.No.,%
            \Name=Name%
            }{%
                \PrintIfRegNumberIsInMarks{\RegNo}{\Name}{#2}%
            }%
    \end{tabular}%
}%


\begin{document}
\DTLloaddb{NamesDB}{namespgf.csv}
%\PrintNamesDTLTable{NamesDB}% Useful for debugging

\DTLloaddb{MarksDB}{markspgf.csv}
%\PrintMarksDTLTable{MarksDB}% Useful for debugging

\PrintNamesWithMarksDTLTable{NamesDB}{MarksDB}
\end{document}

答案3

我知道您只是在寻找pgfplotstable解决方案,但作为思考的素材,我将添加另一个选项。这使用namespgf.csv来生成一组键值对。写下标记时,将插入与注册号相对应的名称。我制作了几个包含约 3000 个条目的模拟电子表格(使用数字而不是名称),编译大约需要 15 秒。我不确定pgfplotstable在效率方面这与解决方案相比如何。请注意,为了简化一些事情,我从数据中删除了标题并手动将它们添加到表中。

\documentclass{article}

\usepackage{xparse}
\usepackage{booktabs}
\usepackage{longtable}
\usepackage{filecontents}

\begin{filecontents*}{namespgf.csv}
5501,Kathirvelu A
5502,Gugan K
5503,Kalaitchelvi S
5504,Suresh S
5505,Mahesh K
\end{filecontents*}
%
\begin{filecontents*}{markspgf.csv}
5501,67
5502,25
5503,62
5505,95
\end{filecontents*}

\ExplSyntaxOn
\tl_new:N \g_tab_rows_tl
\ior_new:N \g_names_ior
\ior_new:N \g_marks_ior
\prop_new:N \g_names_prop

\ior_open:Nn \g_names_ior {namespgf.csv}
\ior_open:Nn \g_marks_ior {markspgf.csv}

\cs_new:Npn \set_name_keys:w #1,#2\q_stop
    {
        \prop_put:Nnn \g_names_prop {#1} {#2}% reg number is the key and name is the value
    }

\cs_new:Npn \tab_write_keys:w #1,#2\q_stop % data from grades sheet
    {
        \prop_gpop:NnN \g_names_prop {#1} \l_tmpa_tl % pop the name for the reg number
        \tl_gput_right:Nn \g_tab_rows_tl {#1&} % number 1st
        \tl_gput_right:NV \g_tab_rows_tl \l_tmpa_tl % name 2nd
        \tl_gput_right:Nn \g_tab_rows_tl {&#2\\} % grade 3rd
    }

\ior_str_map_inline:Nn \g_names_ior
    {
        \set_name_keys:w #1\q_stop
    }

\ior_str_map_inline:Nn \g_marks_ior
    {
        \tab_write_keys:w #1\q_stop
    }

\ior_close:N \g_names_ior
\ior_close:N \g_marks_ior

\NewDocumentCommand { \WriteRows } {}
    {
        \tl_use:N \g_tab_rows_tl
    }

\ExplSyntaxOff

\begin{document}

\begin{longtable}{clc}
Reg.No.&Name&Marks\\
\toprule
\WriteRows
\bottomrule
\end{longtable}

\end{document}

相关内容