TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Suppose that two lists of identical length have been defined with e.g., etoolbox. Is it possible to have a function \do taking two parameters that will process both lists simultaneously, taking one parameter from each list?

For example, suppose one list contains text and the second, URL, would it be possible to have a \do#1#2 function that would return \hyperref[#1]{#2} go through both lists simultaneously?

I am thinking of etoolbox's dolistloop but with two lists given as parameters instead of just one.

A small (necessarily incomplete) MWE

\documentclass{article}
\usepackage{etoolbox}

\documentclass{article}
\usepackage{etoolbox}

\newcommand*\listone{}
\newcommand*\listtwo{}

\forcsvlist{\listadd\listone}{A,B,C}
\forcsvlist{\listadd\listtwo}{x,y,y}

\def\do#1#2{\hyperref[#1]{#2}}

% \dotwolistloop{\listone}{\listwo} This is the instruction I am looking for.

\end{document}

In reality, I need to be able to process three lists simultaneously, so please hints to solutions what would be easy to extend to more than two lists.

share|improve this question
    
There are already two answers -- I don't think this is possible with etoolbox at all. – Christian Hupfer Mar 6 at 6:16
up vote 3 down vote accepted

this iterates through three lists, executing the three argument command \testlist at each stage.

enter image description here

\documentclass{article}

\def\listone{A,B,C}
\def\listtwo{x,y,z}
\def\listthree{1,2,3}

\newcommand\testlist[3]{[#1][#2][#3]\par}
\makeatletter

\def\loopthree#1#2#3{%
\edef\tmp{\noexpand\xthree
\unexpanded\expandafter{#1},\relax
\unexpanded\expandafter{#2},\relax
\unexpanded\expandafter{#3},\relax
}\tmp}


\def\xthree#1,#2\relax#3,#4\relax#5,#6\relax{%
\testlist{#1}{#3}{#5}%
\def\tmp{#2}%
\ifx\empty\tmp
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
{\xthree#2\relax#4\relax#6\relax}}

\makeatother

\begin{document}

\loopthree\listone\listtwo\listthree

\end{document}
share|improve this answer
    
Perhaps, it would be better to use a delimiter, like \@@@, that it is not as easy for a user to include in a list by accident as \relax is. – Gustavo Mezzetti Mar 5 at 22:58
    
@GustavoMezzetti yes actually in this form the delimiter is never tested with \ifx so can be any unique csname, so as you say something other than \relax could be used. – David Carlisle Mar 5 at 23:03
    
Thanks @David Carlisle. With your help, I was able to make the above loopthree macro be compatible with lists created by etoolbox. I added an "answer" below. – Denis Cousineau Mar 7 at 20:24

You can use expl3 and xparse:

\documentclass{article}
\usepackage{xparse}
\usepackage{hyperref}

\ExplSyntaxOn

\NewDocumentCommand{\addtolist}{mm}
 {% #1 = list name; #2 = items
  \seq_clear_new:c { l_denis_list_#1_seq }
  \clist_map_inline:nn { #2 }
   {
    \seq_put_right:cn { l_denis_list_#1_seq } { ##1 }
   }
 }
\NewDocumentCommand{\twolistloop}{mmm}
 {% #1 = first list name; #2 = second list name; #3 = two argument macro
  \seq_mapthread_function:ccN { l_denis_list_#1_seq } { l_denis_list_#2_seq } #3
 }
\ExplSyntaxOff

\newcommand{\makehref}[2]{\href{#1}{#2}\par}

\addtolist{texts}{\TeX\ @ SX,Google,Yahoo}
\addtolist{urls}{
  http://tex.stackexchange.com,
  http://google.com,
  http://yahoo.com
}

\begin{document}

\twolistloop{urls}{texts}{\makehref}

\end{document}

The macro \addtolist appends items to a sequence, creating it if it doesn't exist yet. The \twolistloop macro uses two sequences, passing an item from each to the two parameter macro given as third argument.

In the example I used \href, by hiding it in another macro in order to be able to add \par at the end of each call.

Each line is a link to the corresponding site.

enter image description here

share|improve this answer

With the solution proposed by David Carlisle above, I changed a little the macro so that it works with lists created from etoolbox. The only two differences are that (1) etoolbox lists are separated with a catcode 3 | character (instead of a comma) (2) the list already ends with a delimiters (whereas David above manually added one last comma at the end of the lists). So the whole code is

\documentclass{article}

\usepackage{etoolbox}

% with etoolbox lists
\newcommand*\listone{}
\newcommand*\listtwo{}
\newcommand*\listthree{}
\forcsvlist{\listadd\listone}{A,B,C}
\forcsvlist{\listadd\listtwo}{x,y,y}
\forcsvlist{\listadd\listthree}{1,2,3}

\makeatletter
  \catcode`\|=3

  \def\loopthree#1#2#3{%
    \edef\tmp{\noexpand\xthree
      \unexpanded\expandafter{#1}\relax  % no added delimiter here
      \unexpanded\expandafter{#2}\relax  % no added delimiter here
      \unexpanded\expandafter{#3}\relax  % no added delimiter here
    } \tmp
  }

  \def\xthree#1|#2\relax#3|#4\relax#5|#6\relax{%
    \dothree{#1}{#3}{#5}%
    \def\tmp{#2}%
    \ifx\empty\tmp
      \expandafter\@gobble
    \else
      \expandafter\@firstofone
    \fi
    {\xthree#2\relax#4\relax#6\relax}
  }

  \catcode`\|=12
\makeatother

\begin{document}

% as per David answer:
\newcommand\dothree[3]{[#1][#2][#3]\par}
\loopthree\listone\listtwo\listthree

% as a new example of the use of the dothree macro
Here is all three lists:
\renewcommand\dothree[3]{\item #1 + #2 + #3}
\begin{itemize}
  \loopthree\listone\listtwo\listthree
\end{itemize}

\end{document}

Thank you very much for your help.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.