Populating tabular with etoolbox list

Use \forlistloop instead:

\documentclass{article}

\usepackage{etoolbox}

\newcommand{\pcodo}[1]{Person: & #1 \\}

\listadd\mylist{Ana}
\listadd\mylist{Bob}
\listadd\mylist{Cole}

\newcommand*{\pco}{\forlistloop{\pcodo}{\mylist}}

\begin{document}

\begin{tabular}{r | l}
\pco
\end{tabular}

\end{document}

There are better ways, though. Here's an implementation that's similar to the one with \xintFor, but allows for incrementally building the list.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

% initialize a list
\NewDocumentCommand{\newlist}{m}
 { % #1=list name
  \seq_new:c { g_wasabi_list_#1_seq }
 }

% populate a list one item at a time
\NewDocumentCommand{\addtolist}{mm}
 {
  \seq_gput_right:cn { g_wasabi_list_#1_seq } { #2 }
 }

% use a list; "pre" and "post" are code executed before and after the loop
\NewDocumentCommand{\uselist}{mO{}mO{}}
 { % #1=list name, #2=pre, #3=template, #4=post
  \cs_gset:Nn \__wasabi_list_temp:n { #3 }
  #2
  \seq_map_function:cN { g_wasabi_list_#1_seq } \__wasabi_list_temp:n
  #4
 }

\ExplSyntaxOff

\newlist{my}

%% these commands can go anywhere, provided they are before
%% using the list
\addtolist{my}{Ana}
\addtolist{my}{Bob}
\addtolist{my}{Cole}

\begin{document}

\uselist{my}
  [\begin{tabular}{r|l}]
  {Person & #1 \\}
  [\end{tabular}]

\bigskip

\uselist{my}{#1, }

\end{document}

A list can be used in several ways, with different templates.

enter image description here


With tabulars, it is often easier to build up (i.e., successively concatenate) a token list and then dump it into the input stream at the end of the process.

\documentclass{article}

\usepackage{etoolbox}

\listadd\mylist{Ana}%
\listadd\mylist{Bob}%
\listadd\mylist{Cole}%

\newtoks\tabtoks
\newcommand*{\pco}{%
    \tabtoks{}%
    \newcommand*{\ZaZa}[1]{\tabtoks\expandafter{\the\tabtoks Person: & ##1 \\}}%
    \forlistloop\ZaZa{\mylist}%
    \the\tabtoks%
}

\begin{document}
    \begin{tabular}{r | l}
        \pco
    \end{tabular}
\end{document}

enter image description here

However, thanks to jfbu for noting the problem can be solved more simply than that. The problem with the OP's code is that the & column separator creates a different scope under \halign, and so one must work within that constraint of making things globally available to the other tabular cells. For example, in the OP's original code, merely changing \renewcommand*{\do}[1]{Person: & ##1 \\} to \gdef\do##1{Person: & ##1 \\} makes the code produce the proper output. However, thanks to egreg for noting that redefining \do globally is not acceptable and pointing to \forlistloop as the optimal alternative.

jfbu proposed the following resolution:

\newcommand*{\pco}{%
  \gdef\ZaZa##1{Person: & ##1 \\}%
  \forlistloop\ZaZa{\mylist}%
}

resulting in code that works.

\documentclass{article}

\usepackage{etoolbox}

\listadd\mylist{Ana}%
\listadd\mylist{Bob}%
\listadd\mylist{Cole}%

\newcommand*{\pco}{%
  \gdef\ZaZa##1{Person: & ##1 \\}%
  \forlistloop\ZaZa{\mylist}%
}

\begin{document}
    \begin{tabular}{r | l}
        \pco
    \end{tabular}
\end{document}

Alongside the excellent other two answers, I can propose this one which needs no definition of an extra macro:

\documentclass{article}

\usepackage{xinttools}

\newcommand\mylist{Ana, Bob, Cole}

\begin{document}
    \begin{tabular}{r | l}
        \xintFor #1 in \mylist \do{Person: & #1 \\}
    \end{tabular}

% or \xintFor #1 in {Ana, Bob, Cole}
% or \xintFor* #1 in {{Ana}{Bob}{Cole}}
\end{document}