Get n-th element of a list (with etoolbox, or not)

If you need repeated access to arbitrary items then an "array" of command names \mylist1, \mylist2\ ... might be more suitable than a list.

\documentclass{minimal}

\usepackage{etoolbox}

\newcounter{mylistcounter}

\def\saveitem#1{%
\stepcounter{mylistcounter}%
\expandafter\def\csname mylist\themylistcounter\endcsname{#1}}

\forcsvlist{\saveitem}{%
   first element,
   second element,
   third element,
   fourth element,
   fifth element
}%


\def\getnthelement#1{\csname mylist#1\endcsname}


\begin{document}


\begin{itemize}
\item The third element is: ``\getnthelement{3}''.
\item The fourth element is: ``\getnthelement{4}''.
\item The fourth element again: ``\getnthelement{4}''.
\item The fifth element is: ``\getnthelement{5}''.
\end{itemize}
\end{document}

Here's a possible solution with xparse:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newgniourflist}{ m }
 {
  \seq_new:c { g_gniourf_#1_seq }
 }
\newgniourflist{gniourflist}
\NewDocumentCommand{\addtogniourflist}{ O{gniourflist} m }
 {
  \seq_gput_right:cn { g_gniourf_#1_seq } { #2 }
 }
\NewExpandableDocumentCommand{\getnthelement}{ O{gniourflist} m }
 {
  \seq_item:cn { g_gniourf_#1_seq } { #2 }
 }
\NewDocumentCommand{\storenthelement}{ O{gniourflist} m m }
 {
  \cs_set:Npx #3 { \seq_item:cn { g_gniourf_#1_seq } { #2 } }
 }
\NewDocumentCommand{\cleargniourflist}{ O{gniourflist} }
 {
  \seq_gclear:c { g_gniourf_#1_seq }
 }
\ExplSyntaxOff

\newcommand{\fourthelement}{\getnthelement{4}}

\begin{document}

\addtogniourflist{first element}
\addtogniourflist{second element}
\addtogniourflist{third element}
\addtogniourflist{fourth element}
\addtogniourflist{fifth element}

\begin{itemize}
\item The third element is: ``\getnthelement{3}''.
\item The fourth element is: ``\fourthelement''.
\item The fourth element again: ``\fourthelement''.
\item The fifth element is: ``\getnthelement{5}''.
\end{itemize}

\storenthelement{4}{\playaroundelement}

\texttt{\meaning\playaroundelement}

\end{document}

The last lines show that the macro \playaroundelement is defined to expand just to fourth element.

With these macros you can manage more than one list; the default one is called gniourflist; if you want to clear it, you simply issue \cleargniourflist. But you can say

\newgniourflist{anotherlist}

and use the newlist as before, just adding an optional argument:

\addtogniourflist[anotherlist]{something}
\getnthelement[anotherlist]{1}
\storenthelement[anotherlist]{1}{\someelement}
\cleargniourflist[anotherlist]

The following solution too is fast and defines one macro to hold the entire list. David Carlisle's scheme defines as many macros as there are list items. I don't know which one, between this one and David Carlisle's solution, requires less resources.

\documentclass{minimal}
\usepackage{etoolbox}
\makeatletter
\newcount\listcount
\def\list@list{}
\def\do#1{%
  \advance\listcount\@ne
  \edef\list@list{%
    \unexpanded\expandafter{\list@list}%
    \the\listcount{\unexpanded{#1}}%
  }%
}
\forcsvlist\do{%
  first element,second element,third element,fourth element,fifth element
}
% \getelement{<number>}
\def\getelement#1{%
  \def\reserved@a##1#1##2##3\listmark{%
    \edef\reserved@a{\unexpanded{##2}}%
    \ifx\reserved@a\@nnil
      \@latexerr{No item number '#1'}\@ehd
    \else
      ##2%
    \fi
  }%
  \expandafter\reserved@a\list@list#1{\@nil}\listmark
}
\makeatother
\begin{document}
\begin{itemize}
\item The third element is: ``\getelement{3}''.
\item The fourth element is: ``\getelement{4}''.
\item The fourth element again: ``\getelement{4}''.
\item The fifth element is: ``\getelement{5}''.
% This gives error:
%\item The non-existent element is: ``\getelement{100}''.
\end{itemize}
\end{document}

If you were to prettify your list as, e.g.,

\forcsvlist\do{%
  first element  ,
  second element ,
  third element  ,
  fourth element ,
  fifth element
}

the spaces before the list items are rightly removed by \forcsvlist (via \@iden), but not the spaces after the list items. In that case, list normalization is required.

Even without prettifying the list, the space after fifth element is retained. Look at your output. To avoid the trailing space, add the comment sign at the end of the list: fifth element%.

EDIT

Here is a solution that normalizes the list and is expandable. I still prefer this iterative solution to defining as many commands as the number of list items.

\documentclass{minimal}
\usepackage{catoptions}
\makeatletter
\newcount\gnilistcount
% \addlistitems{<listcmd>}{<items>}
\def\addlistitems#1#2{%
  \ifdefTF#1{}{\def#1{}}%
  \cptfor#2\dofor{%
    \advance\gnilistcount\@ne
    \edef#1{%
      \unexpanded\expandafter{#1}%
      \the\gnilistcount{\unexpanded{##1}}%
    }%
  }%
}
% \getelement{<number>}{<listcmd>}
\def\getelement#1#2{%
  \expandafter\gni@getelement#2\@nil\@nil\listmark{#1}%
}
\def\gni@getelement#1#2#3\listmark#4{%
  \ifstrcmpTF{#1}\@nil{%
    \@latexerr{No item number '#4'}\@ehd
  }{%
    \ifnumcmpTF#1=#4{%
      #2%
    }{%
      \gni@getelement#3\listmark{#4}%
    }%
  }%
}
 \makeatother

% Examples:
\addlistitems\gnilist{%
  first element  ,
  second element ,
  third element  ,
  fourth element ,
  fifth element
}
% Get third element in an \edef:
\edef\x{\getelement{3}\gnilist}
%\show\x

\begin{document}
\begin{itemize}
\item The third element is: ``\getelement{3}\gnilist''.
\item The fourth element is: ``\getelement{4}\gnilist''.
\item The fourth element again: ``\getelement{4}\gnilist''.
\item The fifth element is: ``\getelement{5}\gnilist''.
% This gives error:
%\item The non-existent element is: ``\getelement{100}\gnilist''.
\end{itemize}
\end{document}

Here is a more general \addlistitems that also normalizes the list before saving it.

\documentclass{minimal}
\usepackage{catoptions}
\makeatletter
% \addlistitems[<optional parser>]{<listcmd>}{<items>}
% \addlistitems*[<optional parser>]{<listcmd>}{<itemcmd>}
% The same item may be entered more than once, but with different
% serial numbers. If this isn't the desired spec, then the OP should
% say so.
\robust@def*\addlistitems{\cpt@teststopt\gni@addlistitems,}
\robust@def*\gni@addlistitems[#1]#2#3{%
  \begingroup
  \ifdefTF#2{}{\def#2{}}%
  \edef\tempb{\cptremovescape#2}%
  \ifcsndefTF{listcount@\tempb}{}{%
    \csn@xdef{listcount@\tempb}{0}%
  }%
  \def\csv@do##1{%
    \aftercsname\cptpushnumber{listcount@\tempb}%
    \edef#2{%
      \unexpanded\expandafter{#2}%
      \usecsn{listcount@\tempb}{\unexpanded{##1}}%
    }%
  }%
  \edef\tempa{\csv@@parse\ifcpt@st*\fi}%
  \tempa[#1]{#3}%
  \postgroupdef#2\endgroup
}
% \getelementofnumber{<number>}{<listcmd>}
% This can be used for a general list command <listcmd>.
\new@def*\getelementofnumber#1#2{%
  \expandafter\gni@getelement#2\@nil\@nil\listmark{#1}%
}
\new@def*\gni@getelement#1#2#3\listmark#4{%
  \ifstrcmpTF{#1}\@nil{%
    \@latexerr{No item number '#4'}\@ehd
  }{%
    \ifnumcmpTF#1=#4{%
      #2%
    }{%
      \gni@getelement#3\listmark{#4}%
    }%
  }%
}
\makeatother

% Example:
\addlistitems\gnilist{%
  element 1 ,
  element 2 ,
  element 3 ,
  element 4 ,
  element 5
}
% The list separator is changed here:
\addlistitems[;]\gnilist{%
  element 6  ;
  element 7  ;
  element 8  ;
  element 9  ;
  element 10 ;
  % If you don't want 'element 10' entered twice, say so:
  element 10 ;
}
%\show\gnilist

% Get element no. 3 in an \edef:
\edef\x{\getelementofnumber{3}\gnilist}
%\show\x

\def\getel#1{\getelementofnumber{#1}\gnilist}

\begin{document}
\begin{itemize}
\item The third element is: ``\getel{3}''.
\item The fourth element is: ``\getel{4}''.
\item The fourth element again: ``\getel{4}''.
\item The fifth element is: ``\getel{5}''.
\item The ninth element is: ``\getel{9}''.
% This gives error:
%\item The non-existent element is: ``\getel{100}''.
\end{itemize}
\end{document}