\documentclass[a4paper]{article}
\makeatletter
\def\MakeArray#1#2{% #1: macro that expands to the list, #2: final number
\toks@={1}\@tempcnta=\@ne
\loop\ifnum\@tempcnta<#2\relax
\advance\@tempcnta\@ne
\toks@=\expandafter{\the\expandafter\toks@\expandafter,\number\@tempcnta}%
\repeat
\edef#1{{\the\toks@}}%
}
\makeatother
\begin{document}
\MakeArray\MyArray{4}
\texttt{\meaning\MyArray} % should print macro:->{1,2,3,4}
\end{document}
Doing this with \foreach is (almost) impossible, because \edef doesn't perform assignments, only expansion, and \foreach does tens of assignments to work. You can see from the code that the \edef I do is just the last thing of the ">1" case (there's no check that the input is sensible, so be careful to say something like \MakeArray\MyArray{x} that would die horribly.
The idea is simple: I put 1 in the token register \toks@ and then loop until the scratch counter \@tempcnta reaches the value #2, augmenting the tokens in \toks@.
The curious line
\toks@=\expandafter{\the\expandafter\toks@\expandafter,\number\@tempcnta}
deserves an explanation. After \toks@= TeX wants to see an open brace (after expansion), so it expands the following token, which is \expandafter; good, this expands after the open brace and the token it finds is \the. Well, \the needs to see some specific kinds of (unexpandable) tokens after it, so it expands in order to see what really comes along; the \expandafter expands the following \expandafter which finally expands \number! Now \the performs its duty, in this case to "free" the contents of \toks@. So, if \@tempcnta=2, TeX is presented with
\toks@={1,2}
exactly what we needed.
A different method, which is much more easily customizable, is using expl3.
\documentclass[a4paper]{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\MakeArray}{ m m }
{% #1: macro that expands to the list, #2: final number
\jeremie_make_array:n { #2 }
\tl_set_eq:NN #1 \l__jeremie_array_temp_tl
}
\tl_new:N \l__jeremie_array_temp_tl
\seq_new:N \l__jeremie_array_temp_seq
\cs_new_protected:Npn \jeremie_make_array:n #1
{
\seq_clear:N \l__jeremie_array_temp_seq
\int_step_inline:nnnn { 1 } { 1 } { #1 }
{
\seq_put_right:Nn \l__jeremie_array_temp_seq { ##1 }
}
\tl_set:Nx \l__jeremie_array_temp_tl { \seq_use:Nn \l__jeremie_array_temp_seq { , } }
}
\ExplSyntaxOff
\begin{document}
\MakeArray\MyArray{4}
\texttt{\meaning\MyArray} % should print macro:->{1,2,3,4}
\MakeArray\MyArray{1}
\texttt{\meaning\MyArray} % should print macro:->{1}
\MakeArray\MyArray{0}
\texttt{\meaning\MyArray} % should print macro:->
\end{document}

1for performance reasons? – jeremie Jul 20 '11 at 12:15