3

Is there a way to store the text between the \begin and \end commands of a generic environment in an array?

A code that obviously doesn't work but shows what I mean is the following

\documentclass{memoir}
\usepackage{arrayjobx}
\newarray\entry
\newnvironment{mycenter}{\begin{center}\entry{0}={}{}\end{center}} % \entry{0} should be the text between \begin{mycenter} and \end{mycenter}
\begin{document}
\begin{mycenter}
This line is centered.
\end{mycenter}
\entry{0} % \entry{0} should be 'This line is centered'
\end{document}

Here I used the environment mycenter based on center, but the specific environment doesn't really matter, I just used it as an example.

Edit: I tried using the environ package as suggested by David Carlisle but I think I'm missing something here.

The edited code is

\documentclass{memoir}
\usepackage{arrayjobx, environ}
\newarray\entry
\NewEnviron{mycenter}{\entry(0)={\BODY}\begin{center}\BODY\end{center}}
\begin{document}
\begin{mycenter}
This line is centered.
\end{mycenter}
\entry(0)
\end{document}

which still doesn't compile. What am I doing wrong?

  • you can use the environ (or newenviron) packages to grab the content of the environment as a macro. (tex doesn't really have arrays, so it's not clear if the array-like syntax of the arrayjobx package really helps here, it would be simpler and considerably more efficient to handle the macro storage direct;y) but it depends what you want to do with the stored values. – David Carlisle Feb 1 at 14:04
  • Indeed, it would be much better to know what you want to use the stored values for. – egreg Feb 1 at 14:26
  • I'm making a list of theorems, I want to store the value of each theorem thesis, i.e. the text between \begin{thm} and \end{thm} in an array and use a forloop to build the list once I have all the theorems. So in short, the values of the array will be texts. I'm aware that thmtools offers a \listoftheorems command, but that's now what I'm looking for. @DavidCarlisle could you show me how to use the environ (or newenviron) packages to do that? – noibe Feb 1 at 14:45
  • I don't see how the array syntax helps, unless you want random access, eg to refer to item 42 without accessing item 41 first, but also here you are defining a new environment mycenter so you could define it with \NewEnviron instead which would give you the content as \BODY but it's rather different if you want to do similar with theorems which you are presumably defining already with a custom \newtheorem declaration. – David Carlisle Feb 1 at 14:50
  • @DavidCarlisle that's true but the workaround is immediate: let's say I have something like \newtheorem{mythm}{some code}, then I can define a new environment \newenvironment{thm}{\begin{mythm}}{\end{mythm}}. – noibe Feb 1 at 15:44
5

Definitely not a simple task.

\documentclass{article}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{environ}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\newtheoremx}{momo}
 {
  % * Let's duplicate the working of \newtheorem; \newtheoremx should
  %   be used for theorems that need to be listed
  % * \newtheoremx{theorem}{Theorem} will actually do
  %   \newtheorem{theorem@inner}{Theorem} (honoring the usual optional arguments)
  % * We also need a property list to store along with the theorem
  %   the one which it is subordinate to
  \IfValueTF{#2}
   {
    \newtheorem{#1@inner}[#2@inner]{#3}
    % #1 is subordinate to #2
    \prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #2 }
   }
   {
    \IfValueTF{#4}
     {
      \newtheorem{#1@inner}{#3}[#4]
     }
     {
      \newtheorem{#1@inner}{#3}
     }
    % #1 is not subordinate, store the name itself
    \prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #1 }
   }
  % define a "grabbing" environment #1 with the usual features 
  \NewEnviron{#1}[1][]
   {
    % start the inner environment (without or with optional argument)
    \tl_if_empty:nTF { ##1 }
     { \begin{#1@inner} }
     { \begin{#1@inner}[##1] }
    % save the statement number
    \tl_gset:Nx \g__riccardo_theorems_number_tl { \use:c {@currentlabel} }
    % typeset the statement
    \BODY
    % end the inner environment
    \end{#1@inner}
   % store the statement in a sequence variable, actually as
   % four arguments as shown
   \seq_gput_right:Nx \g_riccardo_theorems_seq
     {
      { #1 } % name
      { \g__riccardo_theorems_number_tl } % number
      { \exp_not:n { ##1 } } % attribution
      { \exp_not:V \BODY } } % body
    }
 }

% allocate the needed variables
\prop_new:N \g_riccardo_theorems_prop
\seq_new:N \g_riccardo_theorems_seq
\tl_new:N \g__riccardo_theorems_number_tl

% print the stored theorems
\NewDocumentCommand{\printtheorems}{}
 {
  % we need a group where nullifying the action of \label
  \group_begin:
  \cs_set_eq:NN \label \use_none:n
  % map the sequence, passing each item to the function that prints a theorem
  \seq_map_function:NN \g_riccardo_theorems_seq \riccardo_printtheorems:n
  % end the group
  \group_end:
 }

\cs_new_protected:Nn \riccardo_printtheorems:n
 {
  % just pass the argument in the form {name}{number}{attribution}{text}
  % to a four argument function
  \__riccardo_printtheorems:nnnn #1
 }
\cs_new_protected:Nn \__riccardo_printtheorems:nnnn
 {
  % redefine \the<statement>@inner to yield the stored number
  % we use the property list to use the correct counter
  % (for instance, in case of "lemma", <statement> will be "theorem"
  \cs_set:cpn { the \prop_item:Nn \g_riccardo_theorems_prop {#1} @inner } { #2 }
  \tl_if_empty:nTF { #3 }
   {
    % no attribution
    \begin{#1@inner} #4 \end{#1@inner}
   }
   {
    % attribution
    \begin{#1@inner}[#3] #4 \end{#1@inner}
   }
 }

\ExplSyntaxOff

\newtheoremx{theorem}{Theorem}[section]
\newtheoremx{lemma}[theorem]{Lemma}

\begin{document}

\section{First test}

\begin{theorem}[Important]\label{thm:important}
This is a theorem about $\log_a x$.
\end{theorem}

\begin{lemma}\label{lem:whatever}
This is a lemma.
\end{lemma}

\begin{theorem}\label{thm:unimportant}
This is another theorem
\end{theorem}

\section{Second test}

\begin{theorem}\label{thm:soandso}
Again a theorem.
\end{theorem}

\section{Theorems}

\printtheorems

\end{document}

enter image description here

  • 1
    Wow! This is brilliant, thank you! I still have a couple of questions: 1) is it possible to use printtheorems at the beginning of each chapter? I was thinking a possible way to do it would be to compile the .tex twice, the first time to get the theorems's thesis and the second one to display them; 2) is it possible to divide printtheorems into chapters? e.g. calling it after every \chapter{chapter x} and displaying only the theorems relative to that specific chapter. – noibe Feb 1 at 17:58
  • 1
    @RiccardoMazzarini That's quite a job! Are you sure you want to have a list of theorems at the beginning of each chapter? Have you ever seen something like that? – egreg Feb 1 at 18:23
  • 1
    I'm sure but I don't want to abuse of your time. If that implementation requires a lot of coding time then don't feel forced to help me. With that said, there's one thing I'd like to ask you: do you know any introductory guides to expl3 and xparse? The documentations of both packages aren't exactly beginner-friendly but they seem (as shown by the code you posted) extremely useful and versatile. – noibe Feb 1 at 18:31
  • A few quick questions. Is there a way to: 1) get a \newpage before each theorem and before \printtheorems 2) in the printtheorems list, making Theorem x (optional theorem name) clickable links to the theorem relative theorem using hyperref 3) this isn't really a question but using \counterwithin{equation}{thm} gives an error, (Class memoir Error: thm is not a counter). – noibe Feb 2 at 12:03
  • 1
    @RiccardoMazzarini 1 is easy, add \newpage where you need it. 2 is more difficult. 3 use \counterwithin{equation}{thm@inner}, if your base theorems are called thm. – egreg Feb 2 at 13:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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