expl3,增加 prop-list 中的一个值

expl3,增加 prop-list 中的一个值

我读取一个 clist 并创建一个 prop-list,它应该表现为一个哈希,其中给定键的值是 clist 中此值的出现次数。下面是我的代码,到目前为止,它确实按预期工作。

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[a4paper]{geometry}
\usepackage{lmodern}
\usepackage[log-declarations=false]{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\Accumulate}
{ m }
{
  \clist_clear_new:N \l_tmpa_clist
  \clist_set:Nn \l_tmpa_clist {#1}

  \prop_clear_new:N \l_tmpa_prop

  \tl_clear:N \l_tmpa_tl
  \tl_clear:N \l_tmpb_tl

  \bool_set_true:N  \l_tmpa_bool % the clist is not void

  \bool_do_while:Nn \l_tmpa_bool
  {
    \par 
    \clist_pop:NNTF \l_tmpa_clist \l_tmpa_tl
    {
      "l_tmpa_tl"~ \tl_use:N \l_tmpa_tl \quad{}
      \prop_if_in:NVTF \l_tmpa_prop \l_tmpa_tl
      {
        % l_tmpa is a key in hash l_tmpa_prop
        % we get the associated value
        \prop_get:NVN \l_tmpa_prop \l_tmpa_tl \l_tmpb_tl
        \tl_show:N \l_tmpb_tl 
        "l_tmpb_tl"~ \tl_use:N \l_tmpb_tl
        % we want it as a number
        \int_set:Nn \l_tmpb_int { \l_tmpb_tl }
        \int_show:N \l_tmpb_int
        \par "l_tmpb_int"~ \int_to_arabic:n { \l_tmpb_tl }
        \int_gincr:N \l_tmpb_int
        % after that the preceding value should be incremented
        \prop_gput:NVn \l_tmpa_prop \l_tmpa_tl { \l_tmpb_int }
      }
      {
        % l_tmpa is not yet a key in hash l_tmpa_prop
        \prop_gput:NVn \l_tmpa_prop \l_tmpa_tl { 1 }
      }
      \prop_show:N \l_tmpa_prop
    }
    {
      \bool_set_false:N \l_tmpa_bool
    }
  }
}

\ExplSyntaxOff


\begin{document}

\Accumulate{1, 2, 3}

\par

\Accumulate{1, 2, 2}

\end{document}

如日志所示,当某个键出现多次时,它不会按预期工作:

The property list \l_tmpa_prop contains the pairs (without outer braces):
>  {1}  =>  {1}.
<recently read> }

l.63 \Accumulate{1, 2, 3}


The property list \l_tmpa_prop contains the pairs (without outer braces):
>  {1}  =>  {1}
>  {2}  =>  {1}.
<recently read> }

l.63 \Accumulate{1, 2, 3}


The property list \l_tmpa_prop contains the pairs (without outer braces):
>  {1}  =>  {1}
>  {2}  =>  {1}
>  {3}  =>  {1}.
<recently read> }

l.63 \Accumulate{1, 2, 3}


The property list \l_tmpa_prop contains the pairs (without outer braces):
>  {1}  =>  {1}.
<recently read> }

l.67 \Accumulate{1, 2, 2}


The property list \l_tmpa_prop contains the pairs (without outer braces):
>  {1}  =>  {1}
>  {2}  =>  {1}.
<recently read> }

l.67 \Accumulate{1, 2, 2}


> \l_tmpb_tl=1.
<recently read> }

l.67 \Accumulate{1, 2, 2}


> \l_tmpb_int=1.
<recently read> }

l.67 \Accumulate{1, 2, 2}

感谢您的阅读,任何帮助都将不胜感激

The property list \l_tmpa_prop contains the pairs (without outer braces):
>  {1}  =>  {1}
>  {2}  =>  {\l_tmpb_int }.
<recently read> }

l.67 \Accumulate{1, 2, 2}

答案1

更简单(在我看来也更短)

使用seq变量,用参数填充它#1并在变量中添加键值\seq_map_inline,用 进行分支\prop_if_in

在我看来,没有必要pop等等push或摆弄变量。tl

如果值应该存在于外部,请使用全局prop变量。

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[a4paper]{geometry}
\usepackage{lmodern}
\usepackage[log-declarations=false]{xparse}

\ExplSyntaxOn

\cs_generate_variant:Nn \int_set:Nn {Nx}

\NewDocumentCommand{\Accu}{m}{%
  \prop_clear:N \l_tmpa_prop
  \seq_set_from_clist:Nn \l_tmpa_seq {#1}%
  \seq_map_inline:Nn \l_tmpa_seq {%
    \prop_if_in:NnTF \l_tmpa_prop {##1} {%
      \int_set:Nx \l_tmpa_int {\prop_item:Nn {\l_tmpa_prop} {##1}}
      \int_incr:N \l_tmpa_int 
      \prop_put:Nnx \l_tmpa_prop {##1} {\int_use:N \l_tmpa_int }
    }{%
      \prop_put:Nnn \l_tmpa_prop {##1} {1}
    }
  }
  \prop_map_inline:Nn \l_tmpa_prop {%
    ##1~ ##2\par
  }
}


\ExplSyntaxOff


\begin{document}

\Accu{1,2,3}

\Accu{1,2,2,3,3,3,4,1,4}

\end{document}

enter image description here

答案2

由于您知道每个键的值都是一个整数,因此您可以在\int_eval:n其中使用它\prop_item:Nn,它是可扩展的。

我提出了一个界面,您可以在其中累积不同的属性列表,还可以选择是否清除属性列表(使用-variant *)。

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\Accumulate}{sO{standard}m}
 {
  % some administrative tasks
  \IfBooleanTF{#1}
   {% no *: clear the property list, creating it if necessary
    \prop_clear_new:c { l_tds_accumulate_#2_prop }
   }
   {% * variant: don't clear the property list, creating it if necessary
    \prop_if_exist:cF { l_tds_accumulate_#2_prop }
     {
      \prop_new:c { l_tds_accumulate_#2_prop }
     }
   }
  % the main function
  \tds_accumulate:nn { #2 } { #3 }
 }

\cs_new_protected:Nn \tds_accumulate:nn
 {
  % do a mapping on the input
  \clist_map_inline:nn { #2 }
   {
    \tds_accumulate_check:nn { #1 } { ##1 }
   }
 }

\cs_new_protected:Nn \tds_accumulate_check:nn
 {
  \prop_if_in:cnTF { l_tds_accumulate_#1_prop } { #2 }
   {% the key is already present: increment its value
    \prop_put:cnx { l_tds_accumulate_#1_prop } { #2 }
     { \int_eval:n { \prop_item:cn { l_tds_accumulate_#1_prop }{#2} + 1 } }
   }
   {% the key is new: put in the value 1
    \prop_put:cnn { l_tds_accumulate_#1_prop } { #2 } { 1 }
   }
 }

\NewDocumentCommand{\showaccumulate}{O{standard}}
 {
  \prop_show:c { l_tds_accumulate_#1_prop }
 }
\ExplSyntaxOff

\Accumulate{1, 2, 3}
\showaccumulate

\Accumulate{1, 2, 2}
\showaccumulate

\Accumulate*{1,2,1,2,1,2,3}
\showaccumulate

\Accumulate[new]{ab,ac,ab,abc}
\showaccumulate[new]

\stop

这是控制台上的结果。

The property list \l_tds_accumulate_standard_prop contains the pairs (without
outer braces):
>  {1}  =>  {1}
>  {2}  =>  {1}
>  {3}  =>  {1}.
<recently read> }

l.50 

? 
The property list \l_tds_accumulate_standard_prop contains the pairs (without
outer braces):
>  {1}  =>  {1}
>  {2}  =>  {2}.
<recently read> }

l.53 

? 
The property list \l_tds_accumulate_standard_prop contains the pairs (without
outer braces):
>  {1}  =>  {4}
>  {2}  =>  {5}
>  {3}  =>  {1}.
<recently read> }

l.56 

? 
The property list \l_tds_accumulate_new_prop contains the pairs (without outer
braces):
>  {ab}  =>  {2}
>  {ac}  =>  {1}
>  {abc}  =>  {1}.
<recently read> }

l.58 \showaccumulate[new]

? 

正如 Bruno LeFloch 在评论中所说,\prop_item:Nn比 慢\prop_get:NnN;这是一个使用后者的版本。

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\Accumulate}{sO{standard}m}
 {
  % some administrative tasks
  \IfBooleanTF{#1}
   {% no *: clear the property list, creating it if necessary
    \prop_clear_new:c { l_tds_accumulate_#2_prop }
   }
   {% * variant: don't clear the property list, creating it if necessary
    \prop_if_exist:cF { l_tds_accumulate_#2_prop }
     {
      \prop_new:c { l_tds_accumulate_#2_prop }
     }
   }
  % the main function
  \tds_accumulate:nn { #2 } { #3 }
 }

\cs_new_protected:Nn \tds_accumulate:nn
 {
  % do a mapping on the input
  \clist_map_inline:nn { #2 }
   {
    \tds_accumulate_check:nn { #1 } { ##1 }
   }
 }

\cs_new_protected:Nn \tds_accumulate_check:nn
 {% check whether the key already exists
  \prop_get:cnNTF { l_tds_accumulate_#1_prop } { #2 } \l__tds_accumulate_temp_tl
   {% the key already exists: increment its value
    \prop_put:cnx { l_tds_accumulate_#1_prop } { #2 }
     { \int_eval:n { \l__tds_accumulate_temp_tl + 1 } }
   }
   {% the key doesn't exist: put 1
    \prop_put:cnn { l_tds_accumulate_#1_prop } { #2 } { 1 }
   }
 }
\cs_generate_variant:Nn \prop_get:NnNTF { c }

\NewDocumentCommand{\showaccumulate}{O{standard}}
 {
  \prop_show:c { l_tds_accumulate_#1_prop }
 }
\ExplSyntaxOff

\Accumulate{1, 2, 3}
\showaccumulate

\Accumulate{1, 2, 2}
\showaccumulate

\Accumulate*{1,2,1,2,1,2,3}
\showaccumulate

\Accumulate[new]{ab,ac,ab,abc}
\showaccumulate[new]

\stop

相关内容