I want to make a newcommand that can take any number of arguments, and concatenate them.
For example
\foo{a}{b}{c}
Will give me \left[a,\ b,\ c\right]
, but should work for any number of variables and not just 3.
Thanks!
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It only takes a minute to sign up.
Sign up to join this communityI strongly believe that a syntax such as \foo{a,b,c}
is much easier than the proposed \foo{a}{b}{c}
, particularly when you have more than three items.
You just need to transform the input to get what you're looking for and this is a job for TeX.
There are several ways to do it, from cooking one for the task at hand to using predefined tools.
I wouldn't use “backslash-space” that adds too wide a space, but that's your choice and you can just replace the \,
in the code below with “backslash space”.
\documentclass{article}
\usepackage{mathtools} % for \DeclarePairedDelimiterX
\ExplSyntaxOn
\DeclarePairedDelimiterX{\foo}[1]{[}{]}
{
\fuzzylumpkins_foo:n { #1 }
}
\clist_new:N \l__fuzzylumpkins_foo_clist
\cs_new_protected:Nn \fuzzylumpkins_foo:n
{
\clist_set:Nn \l__fuzzylumpkins_foo_clist { #1 }
\clist_use:Nn \l__fuzzylumpkins_foo_clist { ,\, }
}
\ExplSyntaxOff
\begin{document}
$\foo{a,b,c}$ $\foo[\big]{a,b,c,d,e,f}$
\bigskip
$\foo*{\dfrac{1}{2},\sqrt{2},x-y}$
\bigskip
$\displaystyle\foo[\bigg]{\sum_{k}a_k,\int f(x)\,dx}$
$\displaystyle\foo*{\sum_{k}a_k,\int f(x)\,dx}$
\end{document}
Note that I avoid adding \left
and \right
, because it doesn't really do what you think. It's better to specify the size manually like in the second example and resort to automatic sizing only when it's really necessary.
Compare the fourth and fifth examples, where I believe that the fourth one looks much better.
“All things are lawful, but not all things are profitable.” 1 Corinthians 10:23
This would be a weird syntax, but it's certainly doable: What you want to do is look at the next character and see if it's a {
and if so, we grab an argument, otherwise, we close the list.
Here's some untested code:
\makeatletter
\def\foo#1{\left[#1\next@foo}
\def\continue@foo#1{
,#1\next@foo
}
\def\next@foo{\@ifnextchar\bgroup\continue@foo\@endfoo}
\def\end@foo{\right]}
\makeatother
this will requre all arguments (except the first) to be enclosed in braces.
It seems easier to pass the list using a single argument list-like format. Here is an implementation using etoolbox
's list processing capabilities:
\documentclass{article}
\usepackage{etoolbox}
% https://tex.stackexchange.com/a/89187/5764
\newcommand{\foo}[2][,\ ]{%
\def\itemdelim{\def\itemdelim{#1}}% Item delimiter delayed by one cycle
\renewcommand*{\do}[1]{\itemdelim##1}% How each item is processed
\left[\docsvlist{#2}\right]}% Process CSV list
\begin{document}
$\left[ a, b, c \right]$
$\left[ a,\ b,\ c \right]$
$\foo{a, b, c}$
$\foo{a,b,c}$
\end{document}
\newcommand{\foo}[1]{\left[ #1 \right]}
, and then use\foo{a, b, c}
.\foo{a, b, c}
should output\left[ a,\ b,\ c \right]
instead?