1

Problem statement

I use the datatool package's \xDTLassignfirstmatch macro to determine the due date of a given assignment (which is identified by a short code such as ex1 or rd2) from a .csv file with a Date column (a list of lecture dates) and a Due column (showing assignments that are due on the respective date).

This approach works fine as long as only one assignment is due per lecture. However, because \xDTLassignfirstmatch requires an exact, not a partial match, it fails if more than one assignment is due on a single date.

So the question is: How can I determine the due date of a given assignment from the .csv data even if one or more other assignments are due the same day?

Minimal (non-)working example

Copy the following code to a file main.tex and compile it with pdflatex main. Then note the TODO comments in the file and edit accordingly.

main.tex

\documentclass{article}

\usepackage{datatool}

\begin{filecontents}{schedule.csv}
Date,Due
2016-02-03,
2016-02-08,rd1
2016-02-10,"ex1, rd2"
\end{filecontents}

% NOTE:  Uncomment only one of the following three lines at a time
\def\assignment{rd1}% Works, because no other assignment is due that day
%\def\assignment{ex1}% TODO: Breaks compilation, because rd2 is due the same day
%\def\assignment{rd2}% TODO: Breaks compilation, because ex1 is due the same day

\DTLloaddb{schedule}{schedule.csv}%
\xDTLassignfirstmatch{schedule}{Due}{\assignment}{\date=Date}%

\begin{document}

\noindent Date: \date

\end{document}

Restrictions

I would like to maintain the structure of schedule.csv as closely as possible. However, if it facilitates a solution, it should be possible to replace the comma, which separates assignments that are due the same day, with a space.

Ideas towards possible solutions

The \DTLifSubString \DTLisinlist macro in the datatool package might be useful for solving this problem, but I think the main challenge is to replace \xDTLassignfirstmatch with some macro that requires only a partial rather than an exact match. I am pretty sure this does not exist in datatool but would have to be written from scratch (or taken from some other package)?

Follow-up question to Ulrike's original solution

Ulrike proposed an xparse-based solution, which works for the given MWE, but fails for my real-world project, because once the assignment due date is extracted, I actually use it to extract further data from schedule.csv.

To illustrate, I am including an edited MWE, which is based on Ulrike's original solution and fails to compile (see TODO note in file) with an Undefined control sequence error. I am looking for a way to get this new MWE to compile.

\documentclass{article}

\usepackage{datatool,xparse}

\begin{filecontents}{schedule.csv}
Date,Due,Foo
2016-02-03,,Bla
2016-02-08,rd1,Moo
2016-02-15,"ex1,rd3",Ha
2016-02-10,"ex1, rd2",Zoo
\end{filecontents}

\DTLloaddb{schedule}{schedule.csv}%

\ExplSyntaxOn


\DTLforeach{schedule}{\scheduledate=Date,\scheduledue=Due}
 {
  \clist_set:NV\l_tmpa_clist{\scheduledue} 
  %\clist_show:N\l_tmpa_clist
  \clist_map_inline:Nn\l_tmpa_clist
   {
    \tl_if_exist:cF
    { g_firstschedule_#1_tl }
    {
     \tl_new:c    {g_firstschedule_#1_tl}
     \tl_gset:cV  {g_firstschedule_#1_tl}{\scheduledate}
    }
   }
 }
\NewDocumentCommand\firstassignment { m }
{
 \tl_use:c {  g_firstschedule_#1_tl } 
}


\ExplSyntaxOff
\begin{document}

Date rd1: \firstassignment {rd1}

Date rd2: \firstassignment {rd2}

Date ex1: \firstassignment {ex1}

Date rd3: \firstassignment {rd3}

% TODO: The following line breaks compilation
\xDTLassignfirstmatch{schedule}{Date}{\firstassignment{rd1}}{\myfoo=Foo}%

\end{document}
  • Imho your database is problematic. In one case (rd1) your assignment is a key word in a row, in the other case it is hidden in a string. While is it probably possible to process this string if would be imho much saner to create two data entries 2016-02-10,ex1 and 2016-02-10, rd2. – Ulrike Fischer Jul 21 '16 at 10:46
  • That is a valid point, which is why I thought it might help to separate assignments that are due on the same date by some symbol other than a comma (see "Restrictions" above). For reasons beyond this MWE, the solution that you propose (two separate date entries) does not work for my situation. All assignments with the same due date must appear in the same table cell. – Florian H. Jul 21 '16 at 11:58
1

You can process the data and retrieve the dates. But be aware that it can get slow if you have lots of entries.

\documentclass{article}

\usepackage{datatool,xparse}

\begin{filecontents}{schedule.csv}
Date,Due
2016-02-03,
2016-02-08,"rd1"
2016-02-10,"ex1, rd2"
2016-02-15,"ex1,rd3"
\end{filecontents}

\DTLloaddb{schedule}{schedule.csv}%

\ExplSyntaxOn


\DTLforeach{schedule}{\scheduledate=Date,\scheduledue=Due}
 {
  \clist_set:NV\l_tmpa_clist{\scheduledue} 
  %\clist_show:N\l_tmpa_clist
  \clist_map_inline:Nn\l_tmpa_clist
   {
    \tl_if_exist:cF
    { g_firstschedule_#1_tl }
    {
     \tl_new:c    {g_firstschedule_#1_tl}
     \tl_gset:cV  {g_firstschedule_#1_tl}{\scheduledate}
    }
   }
 }

\NewDocumentCommand\firstassignment { m }
{
 \tl_use:c {  g_firstschedule_#1_tl } 
}


\ExplSyntaxOff
\begin{document}

Date rd1: \firstassignment {rd1}

Date rd2: \firstassignment {rd2}

Date ex1: \firstassignment {ex1}

Date rd3: \firstassignment {rd3}
\end{document}

Edit for the follow-up.

\xDTLassignfirstmatch expands only once, so you can't use complicated commands, you need to store the value first in some simple macro. Also \NewDocumentCommand creates robust commands which are not expandable. So to get your follow-up working, using \newcommand is better:

\documentclass{article}

\usepackage{datatool,xparse}


\DTLloaddb{schedule}{schedule.csv}%

\ExplSyntaxOn


\DTLforeach{schedule}{\scheduledate=Date,\scheduledue=Due}
 {
  \clist_set:NV\l_tmpa_clist{\scheduledue}
  %\clist_show:N\l_tmpa_clist
  \clist_map_inline:Nn\l_tmpa_clist
   {
    \tl_if_exist:cF
    { g_firstschedule_#1_tl }
    {
     \tl_new:c    {g_firstschedule_#1_tl}
     \tl_gset:cV  {g_firstschedule_#1_tl}{\scheduledate}
    }
   }
 }
\newcommand\firstassignment[1]
{
 \tl_use:c {  g_firstschedule_#1_tl }
}

\ExplSyntaxOff
\begin{document}

Date rd1: \firstassignment {rd1}

Date rd2: \firstassignment {rd2}

Date ex1: \firstassignment {ex1}

Date rd3: \firstassignment {rd3}


\edef\tmpdate{\firstassignment{rd1}}
\xDTLassignfirstmatch{schedule}{Date}{\tmpdate}{\myfoo=Foo}%
\myfoo

\end{document}
  • Beautiful xparse magic, thanks! This solution also works if rd1 is not enclosed by quotation marks (which might well occur if one edits the .csv file in LibreOffice). Note that ex1 here appears in two rows, which would never occur in my application (an assignment can only ever be due on one date). In such a situation, the above solution prints the first date where it encounters the assignment in the .csv file (here: 2016-02-10). Here this happens to coincide with the chronologically earliest date, but if the 2016-02-15 row appeared before the 2016-02-10 one, that would change. – Florian H. Jul 21 '16 at 12:47
  • Yes, I know that it would work without the quotation marks around rd1, but for the sake of consistency I think it is better if every input in this column is treated the same. And I know that it prints the date of the first occurance of a key -- I explictly added a test to show this. – Ulrike Fischer Jul 21 '16 at 12:51
  • I was noting these two properties of your solution for the interest of other readers. Currently trying to use the output of \firstassignment to extract other data from schedule.csv via \xDTLassignfirstmatch, which proves trickier than I thought... – Florian H. Jul 21 '16 at 13:02
  • So if I add a third column Foo to schedule.csv (with arbitrary content) and try to extract data from that column by adding a line \xDTLassignfirstmatch{schedule}{Date}{\firstassignment{rd1}}{\myfoo=Foo} at the end of your solution, compilation fails with an Undefined control sequence error. Any ideas? I'll add another MWE to the original question to illustrate. – Florian H. Jul 21 '16 at 13:11
  • 1
    @FlorianH.: I edited the answer. – Ulrike Fischer Jul 21 '16 at 13:33

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.