15

I have some formula such as z_{(h_{1},h_{2},h_{3})} and z_{(h_{4},h_{5},h_{6})}. How can one introduce a \newcommand{}{} for all of such formulas?

Thanks in advance

4
  • 4
    Please confirm that the only things that differ between the two formulas are the level-two subscripts -- 1/2/3 vs. 4/5/6. Please also confirm that there are always exactly 3 items in the subscript position to the right of z.
    – Mico
    Commented Sep 4, 2017 at 19:15
  • 7
    @Mico: Very optimistic ;-)
    – user31729
    Commented Sep 4, 2017 at 19:16
  • @Mico The difference is only in indices and they have always 3 items in subscript.
    – Fahim B
    Commented Sep 4, 2017 at 19:37
  • @FahimB: What about \zz{1} that produces z_{(h_{1},h_{2},h_{3})}?
    – Werner
    Commented Sep 4, 2017 at 19:54

6 Answers 6

1

They forgot xinttools.

\documentclass{article}

\usepackage{xinttools}

% Thank you very much. I will be very thankful if you write the commands for
% z_{j_{1}(h_{1},h_{2})} and z_{k(h_{3},h_{4},h_{5})}

\newcommand{\zz}[2]{z_{#1(\xintFor ##1 in {#2}\do {h_{##1}\xintifForLast{}{,}})}}
\begin{document}

\[ \zz{j_{1}}{1,2} = \zz{k}{3, 4, 5}\]

\end{document}

enter image description here

0
19
  \newcommand\zz[3]{z_{(h_{#1},h_{#2},h_{#3})} 

then you can use and \zz{1}{2}{3} and \zz{4}{5}{6} or even \zz123 and \zz456

2
  • 8
    +1. I was going to call the macro \zzz, to be mildly mnemonic of the fact that it takes 3 arguments...
    – Mico
    Commented Sep 4, 2017 at 19:43
  • 14
    @Mico and there was I being fearful of Ulrike chiding me for using too many z and you comment I have too few. I can't win. Commented Sep 4, 2017 at 19:44
17

It's not difficult to extend it to any number of subscripts:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\zz}{m}
 {
  z
  \sp{}\sb
   {
    \clist_map_inline:nn { #1 }
     {
      \seq_put_right:Nn \l_fahim_z_subscripts_seq { h\sb{##1} }
     }
    (\seq_use:Nn \l_fahim_z_subscripts_seq { , })
   }
 }
\seq_new:N \l_fahim_z_subscripts_seq
\ExplSyntaxOff

\begin{document}

$\zz{1,2,3}+\zz{4,5,6}=\zz{1,2,3,4,5,6}$

\end{document}

enter image description here

This can be generalized to different base letters and different processing of the subscripts. The trailing optional argument sets how to treat each item in the comma separated list, see the examples.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\zz}{O{z}mO{h\sb{##1}}}
 {
  #1
  \sp{}\sb
   {
    \cs_set_protected:Nn \__fahim_z_subscript:n { #3 }
    \clist_map_inline:nn { #2 }
     {
      \seq_put_right:Nn \l_fahim_z_subscripts_seq { \__fahim_z_subscript:n { ##1 } }
     }
    (\seq_use:Nn \l_fahim_z_subscripts_seq { , })
   }
 }
\seq_new:N \l_fahim_z_subscripts_seq
\ExplSyntaxOff

\begin{document}

$\zz{1,2,3}+\zz{4,5,6}=\zz{1,2,3,4,5,6}$

$\zz[Z]{1,2,3}[k_{#1}]$

$\zz{1,2,3}[(#1)]$

\end{document}

enter image description here

For more complex settings, I suggest a key-value syntax. Here the keys are var (for the name of the variable), outer to set the overall setting (default is just adding the parentheses) and inner for the sequence of actual subscripts. See the given examples. At any moment you can issue \zzset to change (in the current scope) one or more of the values.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\zz}{O{}m}
 {
  \group_begin:
  \keys_set:nn { fahim/zz } { #1 }
  \fahim_zz:n { #2 }
  \group_end:
 }

\NewDocumentCommand{\zzset}{m}
 {
  \keys_set:nn { fahim/zz } { #1 }
 }

\keys_define:nn { fahim/zz }
 {
  var .tl_set:N = \l__fahim_zz_var_tl,
  outer .code:n = \cs_set_protected:Nn \__fahim_zz_outer:n { #1 },
  inner .code:n = \cs_set_protected:Nn \__fahim_zz_inner:n { #1 },
 }

\seq_new:N \l__fahim_zz_subscripts_seq

\cs_new_protected:Nn \fahim_zz:n
 {
  \tl_use:N \l__fahim_zz_var_tl
  \sp{} % a dummy superscript to lower the subscript
  \sb
   {
    \__fahim_zz_outer:n
     {
      \clist_map_inline:nn { #1 }
       {
        \seq_put_right:Nn \l__fahim_zz_subscripts_seq { \__fahim_zz_inner:n { ##1 } }
       }
      \seq_use:Nn \l__fahim_zz_subscripts_seq { , }
     }
   }
 }
\ExplSyntaxOff

% initialize
\zzset{
  var=z,
  outer=(#1),
  inner=h_{#1},
}

\begin{document}

$\zz{1,2,3}+\zz{4,5,6}=\zz{1,2,3,4,5,6}$

$\zz[var=Z,inner=k_{#1}]{1,2,3}$

$\zz[outer=i(#1)]{1,2,3}$

$\zz[outer=i(#1),inner=k_{#1}]{1,2,3}$

\end{document}

enter image description here

3
  • 4
    I've taken the liberty of adding a screenshot. :-)
    – Mico
    Commented Sep 4, 2017 at 20:04
  • Is it possible to use this method for formulas such as z_{i(h_{1},h_{2},h_{3})} and z_{k(h_{4},h_{5})}?
    – Fahim B
    Commented Sep 12, 2017 at 18:12
  • 1
    @FahimB The new version is online.
    – egreg
    Commented Sep 12, 2017 at 21:35
11

It's not difficult to extend it to any number of subscripts and without using ExplSyntaxOn:

\def\zz#1{\zzA#1,,}
\def\zzA#1,{z_\bgroup(h_{#1}\zzB}
\def\zzB#1,{\ifx\end#1\end)\egroup \else ,h_{#1}\expandafter\zzB\fi}

$\zz{1,2,3}+\zz{4,5,6}=\zz{1,2,3,4,5,6}$

\bye

EDIT If you need to add an ``index letter'' (i, j like in your comment), then it is possible to do using this code:

\def\zz#1#{z_\bgroup#1\zzI}
\def\zzI#1{\zzA#1,,}
\def\zzA#1,{(h_{#1}\zzB}
\def\zzB#1,{\ifx\end#1\end)\egroup \else ,h_{#1}\expandafter\zzB\fi}

$\zz i{1,2,3}+\zz j{4,5,6}=\zz{1,2,3,4,5,6}$

\bye
4
  • Is it possible to use this method for formulas such as z_{i(h_{1},h_{2})} and z_{j(h_{3},h_{4},h_{5})}?
    – Fahim B
    Commented Sep 12, 2017 at 19:19
  • @FahimB Yes, see above.
    – wipet
    Commented Sep 12, 2017 at 20:36
  • Thank you very much. I will be very thankful if you write the commands for z_{j_{1}(h_{1},h_{2})} and z_{k(h_{3},h_{4},h_{5})}.
    – Fahim B
    Commented Sep 12, 2017 at 20:54
  • 1
    OK: \zz j_1{1,2} and \zz k{3,4,5}.
    – wipet
    Commented Sep 13, 2017 at 4:10
4

Very easy with the listofitems package:

\documentclass{article}
\usepackage{listofitems}
\newcommand\zz[1]{
  z_{(
    \setsepchar{,}
    \readlist*\zlist{#1}
    \foreachitem\i\in\zlist{\ifnum\icnt=1\relax\else,\fi h_{\i}}
  )}
}
\begin{document}
$\zz{1,2,3}+\zz{4,5,6}=\zz{1,2,3,4,5,6}$
\end{document}

enter image description here

By the way, listofitems works in plain TeX, as well:

\input listofitems.tex
\def\zz#1{
  z_{(
    \setsepchar{,}
    \readlist*\zlist{#1}
    \foreachitem\i\in\zlist{\ifnum\icnt=1\relax\else,\fi h_{\i}}
  )}
}
$\zz{1,2,3}+\zz{4,5,6}=\zz{1,2,3,4,5,6}$
\end
2

You could also use e-TeX. (It seems rather simple to me.) Assuming that you have three subsequent indices every time you would say

\newcommand*\zz[1]{%
  \@tempcnta\numexpr#1+1\relax
  \@tempcntb\numexpr#1+2\relax
  z_{(%
    h_{#1}+h_{\the\@tempcnta}+h_{\the\@tempcntb}%
  )}
}

and then call \zz{1} resp. \zz{4}.

output_solution1

To add in a few generalisations, i.e. arbitrary number of indices and specified indices is not a big deal:

\newcommand*\zzz[2][h]{%
  \def\forplus{\def\forplus{+}}
  z_{(%
    \@for\i:=#2\do{\forplus#1_{\i}}%
  )}
}

Note the optional parameter for the subscripts of first order:

\begin{gather*}
  \zzz{1,2,3}\\
  \zzz{4,5,6}\\
  \zzz[p]{7,11,13,17}
\end{gather*}

output_solution2

If you want to you can get really sophisticated by declaring something that acts like

\indexloop[<delimiter>][<format>]{<indices>}

where <format>:='<superscript>_<opt. delimiter><subscript><opt. delimiter>'

defined by

\makeatletter
\def\defaultsup{z}
\def\defaultsub{h}
\def\defaultdll{(}
\def\defaultdlr{)}
\def\defaultsep{+}
\def\indexloop{%
  \kernel@ifnextchar[
    {\indexl@op}
    {\indexl@op[\defaultsup_\defaultdll\defaultsub\defaultdlr]}
}
\def\indexl@op[#1]{%
  \kernel@ifnextchar[
    {\indexl@@p[{#1}]}
    {\indexl@@p[\defaultsep][{#1}]}
}
\def\indexl@@p[#1][#2]#3{%
  \def\forsep{\def\forsep{#1}}
  \def\customsup{}
  \def\customsub{}
  \def\customdll{}
  \def\customdlr{}
  \process@format#2\@end
  \customsup_{%
    \customdll
    \@for\i:=#3\do{\forsep\customsub_{\i}}%
    \customdlr
  }%
}
\def\process@format#1_#2\@end{%
\def\customsup{#1}
\process@sub#2\@@end
}
\def\process@sub#1{
\ifx#1\@@end\else
  \ifcat#1x
    \edef\customsub{\customsub#1}
  \else
    \ifx\customdll\@empty
      \def\customdll{#1}
    \else
      \ifx\customdlr\@empty
        \def\customdlr{#1}
      \fi
    \fi
  \fi
  \expandafter\process@sub
\fi
}
\makeatother

Here is a short test of the last solution.

\begin{gather*}
  \indexloop{1,2,3}\\
  \indexloop{4,5,6}\\
  \indexloop[z_(p)]{7,11,13,17}\\
  \indexloop[-][z_\langle x\rangle]{8,9,10,12,14,15,16}\\
  \indexloop[,][{a_[i]}]{1,2}
\end{gather*}

output_solution3

Complete Code

% arara: pdflatex
\documentclass{article}
\usepackage{amsmath}

\makeatletter
\newcommand*\zz[1]{%
  \@tempcnta\numexpr#1+1\relax
  \@tempcntb\numexpr#1+2\relax
  z_{(%
    h_{#1}+h_{\the\@tempcnta}+h_{\the\@tempcntb}%
  )}
}
\newcommand*\zzz[2][h]{%
  \def\forplus{\def\forplus{+}}
  z_{(%
    \@for\i:=#2\do{\forplus#1_{\i}}%
  )}
}
\def\defaultsup{z}
\def\defaultsub{h}
\def\defaultdll{(}
\def\defaultdlr{)}
\def\defaultsep{+}
\def\indexloop{%
  \kernel@ifnextchar[
    {\indexl@op}
    {\indexl@op[\defaultsup_\defaultdll\defaultsub\defaultdlr]}
}
\def\indexl@op[#1]{%
  \kernel@ifnextchar[
    {\indexl@@p[{#1}]}
    {\indexl@@p[\defaultsep][{#1}]}
}
\def\indexl@@p[#1][#2]#3{%
  \def\forsep{\def\forsep{#1}}
  \def\customsup{}
  \def\customsub{}
  \def\customdll{}
  \def\customdlr{}
  \process@format#2\@end
  \customsup_{%
    \customdll
    \@for\i:=#3\do{\forsep\customsub_{\i}}%
    \customdlr
  }%
}
\def\process@format#1_#2\@end{%
\def\customsup{#1}
\process@sub#2\@@end
}
\def\process@sub#1{
\ifx#1\@@end\else
  \ifcat#1x
    \edef\customsub{\customsub#1}
  \else
    \ifx\customdll\@empty
      \def\customdll{#1}
    \else
      \ifx\customdlr\@empty
        \def\customdlr{#1}
      \fi
    \fi
  \fi
  \expandafter\process@sub
\fi
}
\makeatother

\begin{document}
\begin{gather*}
  \zz{1}\\
  \zz{4}
\end{gather*}

\begin{gather*}
  \zzz{1,2,3}\\
  \zzz{4,5,6}\\
  \zzz[p]{7,11,13,17}
\end{gather*}

\begin{gather*}
  \indexloop{1,2,3}\\
  \indexloop{4,5,6}\\
  \indexloop[z_(p)]{7,11,13,17}\\
  \indexloop[-][z_\langle x\rangle]{8,9,10,12,14,15,16}\\
  \indexloop[,][{a_[i]}]{1,2}
\end{gather*}
\end{document}

Edit

Even the first solution can be more sophisticated by implementing the step length:

\newcommand*\zz[2][1]{%
  \@tempcnta\numexpr#2+1*#1\relax
  \@tempcntb\numexpr#2+2*#1\relax
  z_{(%
    h_{#2}+h_{\the\@tempcnta}+h_{\the\@tempcntb}%
  )}
}

\[\zz[2]{0}\] would then compile to z_{h_0+h_2+h_4} as expected.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .