使用 expl3 获取键值“列表”的大小并获取列表中的特定元素

使用 expl3 获取键值“列表”的大小并获取列表中的特定元素

我对 Latex 还不太熟悉,我正在尝试构建一个自动报告模板。为此,我想定义一个“列表”(我不确定在这种情况下如何称呼它),其中包含许多键/值对的元素,并能够将它们取回。根据我在论坛上看到的示例,我构建了以下内容:

\documentclass{article}
\usepackage{xparse}
\usepackage{forloop}

\ExplSyntaxOn

% Create DosimetryData property
\prop_new:N \l_pollard_DosimetryData_prop

\cs_generate_variant:Nn \prop_put:Nnn { Nx }

% Define DosimetryData add field to token list function
\cs_new_protected:Nn \pollard_add_property:nn
 {
  \tl_set:Nn \l_pollard_DosimetryData_temp_tl { #1 }
  \keys_set:nn { pollard/DosimetryData } { #2 }
 }

% Set DosimetryData values
\NewDocumentCommand{\DosimetryData}{m}
 {
  \prop_set_from_keyval:Nn \l_pollard_DosimetryData_prop { #1 }
  \prop_map_inline:Nn \l_pollard_DosimetryData_prop { \pollard_add_property:nn { ##1 } { ##2 } }
 }

% Get DosimetryData values
\NewExpandableDocumentCommand{\getDosimetryData}{mm}
{% #1 = node number, #2 = property
\prop_item:Nn \l_pollard_DosimetryData_prop { #1 #2 }
}

% Get DosimetryData number of inputs
\NewDocumentCommand{\getDosimetryDatalength}{}{ \prop_count:N \l_pollard_DosimetryData_prop }

% Define DosimetryData field structure
\keys_define:nn { pollard/DosimetryData }
 {
    Run             .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl   Run }           { #1 },
    DUT             .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl   DUT }           { #1 },
    Samples         .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl   Samples }       { #1 },
    Energy          .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl   Energy }        { #1 },
    Flux            .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl   Flux }          { #1 },
    DoseRate        .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl   DoseRate }      { #1 },
    TID             .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl   TID }           { #1 },
    ProtonFluence   .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl   ProtonFluence } { #1 },
    DDEF            .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl   DDEF }          { #1 },
    
    R     .code:n = \keys_set:nn { pollard/DosimetryData } { Run=#1 },
    D     .code:n = \keys_set:nn { pollard/DosimetryData } { DUT=#1 },
    S     .code:n = \keys_set:nn { pollard/DosimetryData } { Samples=#1 },
    f     .code:n = \keys_set:nn { pollard/DosimetryData } { Flux=#1 },
    E     .code:n = \keys_set:nn { pollard/DosimetryData } { Energy=#1 },
    Dr    .code:n = \keys_set:nn { pollard/DosimetryData } { DoseRate=#1 },
    F     .code:n = \keys_set:nn { pollard/DosimetryData } { ProtonFluence=#1 },
 }

\ExplSyntaxOff

\newcounter{counter}

\begin{document}

\DosimetryData{
1={DUT = BST182,    Run = 1, Samples = 1-6, E = 100, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11    },
2={DUT = BST182,    Run = 2, Samples = 1-6, E = 200, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11    },
3={DUT = BST182,    Run = 2, Samples = 1-6, E = 200, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11    },
4={DUT = BST182,    Run = 2, Samples = 1-6, E = 200, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11    }
}

\noindent
DUT 1 -- name: \getDosimetryData{\value{counter}}{DUT}, Run: \getDosimetryData{\value{counter}}{Run}\\
\noindent
DUT 2 -- name: \getDosimetryData{2}{DUT}, Run: \getDosimetryData{2}{Run}\\


\noindent
\text{Length is \getDosimetryDatalength{1}}
\\

\forloop{counter}{1}{\value{counter} < \inteval{4+1}}{
\noindent
    Counter: \thecounter, Run:  \getDosimetryData{\value{counter}}{Run}\\
}

它有点工作,但只有当我写下元素的编号时我才能获取我的数据,如下所示:

DUT 2 -- name: \getDosimetryData{2}{DUT}, Run: \getDosimetryData{2}{Run}\\

然后,如果我尝试使用计数器或任何“函数”的返回值,它不起作用,我得到一个空白输出:

DUT 1 -- name: \getDosimetryData{\value{counter}}{DUT}, Run: \getDosimetryData{\value{counter}}{Run}\\

我猜是因为当以这种方式调用时,它会检查输入的实际“文本/字符串”而不是“链接”值,但我不知道该怎么做。

然后,我尝试做的另一件事,我猜想它有某种联系,但我无法获取“列表”的大小(即我的示例中的 4)。

我尝试了 prop 和 tl 的 count 函数,但是我不明白返回的数字,它们都不是 4。

我的目标是能够定义这个列表,并能够循环遍历它以获取代码另一部分中的所有元素(基本上是构建一个表格)。

如果有人能帮助我,谢谢!

答案1

我建议拆分您的数据结构。我会将集合名称按顺序排列,并初始化并填充每个数据集的属性列表。

我还改变了您设置剂量测定数据的方式,而不是填充以下使用的属性\keyval_parse:nnn(如果省略了值,则会引发错误),因此,如果您给出类似的输入,则行为会有所不同\DosimetryData{1={<values>}, 1={<values>}},在两种情况下,只有第二个<values>最终出现在数据结构中,但名称1将在存储其名称的序列中放置两次。

序列的优点是您不再需要数字名称来循环数据,您只需提供一个\DosimetryDataLoop使用序列循环所有数据集的宏。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\seq_new:N \l_pollard_DosimetryData_sets_seq
\msg_new:nnn { pollard } { missing-value }
  { Missing~ value~ list~ for~ set~ #1 }

% Set DosimetryData values
\NewDocumentCommand{\DosimetryData}{m}
  {
    \keyval_parse:nnn
      { \msg_error:nnn { pollard } { missing-value } }
      \pollard_add_property:nn
      {#1}
  }

% Define DosimetryData add field to token list function
\cs_new_protected:Nn \pollard_add_property:nn
  {
    \seq_put_right:Ne \l_pollard_DosimetryData_sets_seq {#1}
    \prop_clear_new:c { l_pollard_DosimetryData_ #1 _prop }
    \tl_set:Ne \l_pollard_DosimetryData_temp_tl { #1 }
    \keys_set:nn { pollard/DosimetryData } { #2 }
  }
\cs_generate_variant:Nn \seq_put_right:Nn { Ne }
\cs_generate_variant:Nn \tl_set:Nn  { Ne }

% Get DosimetryData values
\NewExpandableDocumentCommand{\getDosimetryData}{mm}
  {% #1 = node number, #2 = property
    \prop_item:cn { l_pollard_DosimetryData_ #1 _prop } { #2 }
  }

% Get DosimetryData number of inputs
\NewDocumentCommand{\getDosimetryDatalength}{}
  { \seq_count:N \l_pollard_DosimetryData_sets_seq }
\NewDocumentCommand{\getDosimetrySetDatalength}{m}
  { \prop_count:c { l_pollard_DosimetryData_ #1 _prop } }


% Define DosimetryData field structure
\keys_define:nn { pollard/DosimetryData }
 {
    Run             .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { Run } {#1},
    DUT             .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { DUT }           {#1},
    Samples         .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { Samples }       {#1},
    Energy          .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { Energy }        {#1},
    Flux            .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { Flux }          {#1},
    DoseRate        .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { DoseRate }      {#1},
    TID             .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { TID }           {#1},
    ProtonFluence   .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { ProtonFluence } {#1},
    DDEF            .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { DDEF }          {#1},
    
    R     .meta:n = { Run={#1} },
    D     .meta:n = { DUT={#1} },
    S     .meta:n = { Samples={#1} },
    f     .meta:n = { Flux={#1} },
    E     .meta:n = { Energy={#1} },
    Dr    .meta:n = { DoseRate={#1} },
    F     .meta:n = { ProtonFluence={#1} },
 }

\NewDocumentCommand \DosimetryDataLoop { +m }
  { \seq_map_inline:Nn \l_pollard_DosimetryData_sets_seq {#1} }

\ExplSyntaxOff

\newcounter{counter}

\begin{document}

\DosimetryData{
1={DUT = BST182,    Run = 1, Samples = 1-6, E = 100, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11    },
2={DUT = BST182,    Run = 2, Samples = 1-6, E = 200, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11    },
3={DUT = BST182,    Run = 2, Samples = 1-6, E = 200, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11    },
4={DUT = BST182,    Run = 2, Samples = 1-6, E = 200, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11    }
}

\setcounter{counter}{2}
\noindent
DUT 1 -- name: \getDosimetryData{\the\value{counter}}{DUT}, Run:
\getDosimetryData{\the\value{counter}}{Run}\par
\noindent
DUT 2 -- name: \getDosimetryData{2}{DUT}, Run: \getDosimetryData{2}{Run}


\noindent
{Length is \getDosimetryDatalength, Length of set 1 is
\getDosimetrySetDatalength{1}}

\DosimetryDataLoop
  {%
    \noindent
    Set name: #1, Run: \getDosimetryData{#1}{Run}\par
  }
\end{document}

相关内容