4

I've got a large multi-purpose database and i would like to pick several items in it (using labels) and print them in the given order, not the database order or any entry-related order.

For example, i currently use this code (found on this site, thanks to Peter Grill) :

\documentclass{article}  
\usepackage{datatool}
\usepackage{longdata}

\usepackage{filecontents}
\begin{filecontents*}{foo.dat}
Hammer001,   Hammer,    1 ,  0 , 1 , 10 , 1 , light\\
Hammer002,   Hammer,    2 ,  0 , 1 , 10 , 1 , heavy\\
Hammer003,   Hammer,    3 ,  0 , 1 , 10 , 1 , really heavy\\
Longsword001,Longsword, 1 , -1 , 2 , 75 , 2 , one-handed \\
Longsword002,Longsword, 2 , -1 , 2 , 75 , 2 , two-handed \\
Longsword003,Longsword, 3 , -1 , 2 , 75 , 2 , three-handed \\
\end{filecontents*}

\newcommand{\PrintDTLTable}[2]{%
% #1 = database to search
% #2 = list of rowIDs
\begin{enumerate}
\DTLforeach*[\DTLisSubString{#2}{\RowID}]{#1}{%
    \RowID=RowID,%
    \Label=Label,%
    \Cost=Cost,%
    \Weight=Weight,%
    \Description=Description%
    }{%
    \item \Label ; Price=\Cost ; Weight=\Weight ; It's very \Description
}%
\end{enumerate}
}%

\begin{document}

\DTLloaddb[noheader,keys={RowID,Label,Cost,Weight,PropA,PropB,PropC,Description}]{myDB}{foo.dat}

\PrintDTLTable{myDB}{Hammer001,Hammer003,Longsword003}
\end{document}

The command

\PrintDTLTable{myDB}{Hammer001,Hammer003,Longsword003}

is doing exactly what i want except that

\PrintDTLTable{myDB}{Hammer003,Longsword003,Hammer001}

would obviously produce the exact same result.

Is there any way to keep the given order ? (sorry for my poor english)

1 Answer 1

10

\DTLforeach visits the rows one after another. Therefore the row order of the data base matters:

\DTLforeach*[\DTLisSubString{#2}{\RowID}]{#1}{%
 % #2 = list of rowIDs

In the following solution I have put the data extraction in a for loop that iterates over the given row IDs. There are many for loops, e.g. LaTeX's \@for. I am using \comma@parse from package kvsetkeys, because it removes leading and trailing spaces from the entries in the list. Then the row id is compared with \equal to get only exact matches.

\usepackage{kvsetkeys}

\makeatletter
\newcommand{\PrintDTLTable}[2]{%
  % #1 = database to search
  % #2 = list of rowIDs
  \begin{enumerate}
    \comma@parse{#2}{%
      \DTLforeach*[\equal{\comma@entry}{\RowID}]{#1}{%
        \RowID=RowID,%
        \Label=Label,%
        \Cost=Cost,%
        \Weight=Weight,%
        \Description=Description%
      }{%
        \item \Label ; Price=\Cost ; Weight=\Weight ; It's very \Description
        \dtlbreak
      }%
      \@gobble % ignore the entry argument provided by \comma@parse
    }%
  \end{enumerate}
}%
\makeatother

Of course the run time behaviour of this algorithm is poor. For a data base with n entries and m selected rows is is is O(n*m). That means O(n²) if the whole data base is output. Theoretically sorting can be done in O(n*log(n)).

1
  • <sup>2</sup> works on tex.sx as well (and so does <sub>...</sub>).
    – doncherry
    Jul 27, 2012 at 14:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .