4

I am having a problem of using the command of \forlistloop of etoolbox

unlike the way of typical C program where

int a[5]
for ( i = 0; i <5; i++)
{
    a[i]
}

one could access i I am not sure how to access the individual elements of the list using the command.

I see that \forlistloop<handler><list> is the basic sequence that is given.

I tried the following and get errors of undefined sequence.

\def\myrowlist{}
\forcsvlist{\listadd\myrowlist}{r,\theta,z}

$   \newcounter{itemcount}
    %\begin{itemize}
        \forlistloop{\stepcounter{itemcount}\itemRaone}{\myrowlist}
        \itemRaone
    %\item Total: \number\value{itemcount} items
    %\end{itemize}
$

My expectation is that I should be able to extract r, \theta and z separately each time.

cgnieder
  • 66,645
  • Instead of piling up questions after questions you should consider accepting answers to your questions first, showing that you appreciate users' efforts to help you. And please don't post only fragments –  Jul 22 '15 at 09:39
  • Hi Christian,very sorry. Since I am new to this forum I am not sure how to accept an answer. I am thankful for whosoever is replying. But if there is a way to show do it in a formal way do tell me. I am actually not very aware of the rules of the internet and the forum and using it for the first time in my life. – user2714795 Jul 22 '15 at 09:57
  • lists by etoolbox are not random access lists, i.e. you can't extract at once list element like a in C - vector –  Jul 22 '15 at 15:28
  • I think Christian means voting "up" or "down" answers by clicking on the "up" or "down" icons near the top-left of each answer. You are not obligated to vote, of course, but the system is designed so that highly "up-voted" answers will appear near the top of the answer list relative to less highly up-voted answers. The person who asks the question can also "accept" an answer that the questioner thinks best (or adequately or completely or superbly) answers the question. Contributing to this site in this way is helpful to others who need help but may not be able to distinguish between answers. – jon Jul 23 '15 at 02:40
  • @jon: Just to add: I did not mean upvoting/accepting my answer. I answered hours after writing my first comment –  Jul 23 '15 at 04:56
  • @ChristianHupfer -- Indeed! I tried to be "generic" about the process: I assume most people who provide answers (you included) believe that the heuristic value of voting on and accepting answers is more important than the accummulation of acquiring badges and privileges. – jon Jul 23 '15 at 13:17
  • @jon: There are badges? Where do I get them? :D –  Jul 23 '15 at 18:16

3 Answers3

4

Try the routines \grabitem{number} to get the item from the list. It's not failsafe, of course.

In general, it's better to use wrapper commands instead of doing stuff like \forcsvlist{\stepcounter...}{..} directly.

\documentclass{article}

\usepackage{etoolbox}


\listadd\myrowlist{}

\newcounter{itemcount}
\newcommand{\additem}[2][\myrowlist]{%
  \listadd{#1}{#2}%
  \stepcounter{itemcount}%
}%

\newcommand{\addtolist}[2][\myrowlist]{%
  \setcounter{itemcount}{0}
  \let #1\relax
  \listgadd #1{}%
  \forcsvlist{\additem[#1]}{#2}%
}

\makeatletter
\newcounter{temp@@count}

\newcommand{\getitem}[2]{%
  \stepcounter{temp@@count}%
    \ifnumequal{\value{temp@@count}}{#1}{%
      \ensuremath{#2}%
      \listbreak
    }{}
}%

\newcommand{\grabitem}[2][\myrowlist]{%
  \setcounter{temp@@count}{0}
  \ifnumgreater{#2}{\value{itemcount}}{%
    \GenericError{Error}{Number #2 for grabbing item too large}{There are only \number\value{itemcount} items}{Check your code!}
  }{% All is ok.
    \forlistloop{\getitem{#2}}{#1}%
  }
}

\makeatother

\newcommand{\showlist}[1]{%
$#1$

}%



\begin{document}

\addtolist{r,\theta,z,\Gamma,\Delta}

\forlistloop{\showlist}{\myrowlist} 

\grabitem{1}

\grabitem{5}


\begin{itemize}
  \forcsvlist{\item \grabitem[\myrowlist]}{1,3,5,4,5,2}
\end{itemize}



\end{document}
  • I realise I am late in commenting this, but doesn't this make it so that your commands are built to manipulate any list at all, changing at the same time the value of itemcount, which is only related to the number of items in the specific \myrowlist? – sgf Dec 23 '16 at 22:07
  • @thisismynamenow: I never claimed that it would be valid in all cases. –  Dec 25 '16 at 15:17
2

If you are willing to switch from etoolbox to the more powerful expl3 programming environment, you could do like this:

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\newlist}{m}
 {
  \seq_new:c { g_sumanta_lists_#1_seq }
 }
\newlist{myrow} % default

\NewDocumentCommand{\additems}{O{myrow} m}
 {
  \clist_map_inline:nn { #2 }
   {
    \seq_gput_right:cn { g_sumanta_lists_#1_seq } { ##1 }
   }
 }

\NewDocumentCommand{\getitem}{O{myrow} m O{\use:n}}
 {
  \int_compare:nTF { #2 > \seq_count:c { g_sumanta_lists_#1_seq } }
   {
    NO ITEM
   }
   {
    #3 { \seq_item:cn { g_sumanta_lists_#1_seq } { #2 } }
   }
 }

\NewDocumentCommand{\uselist}{O{\use:n}m}
 {
  \seq_map_inline:cn { g_sumanta_lists_#2_seq } { #1 { ##1 } }
 }
\ExplSyntaxOff

\newcommand{\makeitem}[1]{\item $#1$}

\begin{document}

\additems{r,\theta,z,\Gamma}
\additems{\Delta}

\getitem{1}

\getitem{2}[\ensuremath]

\getitem{99}

\begin{itemize}
\uselist[\makeitem]{myrow}
\end{itemize}

\newlist{foo}

\additems[foo]{a,b,c}

\begin{enumerate}
\uselist[\makeitem]{foo}
\end{enumerate}


\end{document}

The optional argument to \additems is a list name (default myrow), the mandatory one is a comma separated list of items.

With \getitem you obtain the item whose number is specified by the mandatory argument; the first optional argument is a list name, the trailing optional argument is a one parameter macro that wraps the item (default is just producing the item). In case the number exceeds the available items, NOITEM is printed; this could be turned into an error message.

The \uselist command takes as optional argument a one parameter macro that should wrap the item. The default is just producing the item.

enter image description here

egreg
  • 1,121,712
2

For iterating over an elementary list of items, you can use an array-like structure/interface (similar to what one would expect in programming languages like C) provided by arrayjobx:

enter image description here

\documentclass{article}
\usepackage{multido,arrayjobx}

\newarray\myrowlist\readarray{myrowlist}{r & \theta & z}

\begin{document}

\newcommand{\itemdelim}{\renewcommand{\itemdelim}{,\,}}% http://tex.stackexchange.com/a/89187/5764
$\multido{\i=1+1}{3}{\itemdelim\myrowlist(\i)}$

\end{document}

Elements within the array is specified using \readarray{<array>} where <array> is an &-delimited sequence.

multido has an easy enough interface to iterate over some \integer sequence.

Werner
  • 603,163