3

I am a Lua novice, and I would like to know if there is any way for an iterator to filter out or skip certain items in a table from a csv file. In particular, I would like for an iterator to be able to take the rows of a table and only operate on rows with certain tags or arguments in a column. Take for example a file file.csv with the following data:

1, not a prime
2, a prime
3, a prime
4, not a prime
5, a prime
6, not a prime
7, a prime
8, not a prime
9, not a prime

I would like the iterator to filter out or skip either the "a prime" entries or the "not a prime" entries.

I have borrowed the following Lua code from another poster which defines functions for interpreting the contents of the file as a table, then printing the table with generic for. This is stored in a separate file, luacode.lua.

function interpretfile()

    local input = io.open('file.csv', 'r')
    primedata = {}

    for line in input:lines() do
        local split = string.explode(line, ",")
        primerow = {}
        primerow.arg1 = split[1]
        primerow.arg2 = split[2]
        table.insert(primedata, primerow)
    end

    input:close()
 end

function printfile()

    for i,p in pairs(primedata) do
       tex.print(string.format("{%s} is{%s} number.\\\\", p.arg1, p.arg2))
    end

end

Finally, the lua functions are made to be interpretable in LaTeX such that the table is printed into a pdf.

\documentclass[12pt]{article}

\directlua{dofile("luacode.lua")}
\def\interpretfile{\directlua{interpretfile()}}
\def\printfile{\directlua{printfile()}}

\begin{document}
\interpretfile
\printfile
\end{document}

Is there a way to get the code in the lua file to print out only certain rows of the csv file, such as those with common entries for the second argument? Is there a better way to get the result I am trying to achieve besides using lua?

1
  • string.explode is not standard Lua, but I guess you have some code defining such a function.
    – frafl
    Apr 26, 2021 at 15:12

2 Answers 2

1

This is how to write an iterator that filters out certain lines before interpreting them:

filtered_lines = function(input,linefilter)
    local nextline = input:lines()
    return function()
        local line = nextline()
        if not line then return nil end
        --linefilter shall return true (or anaything except nil/false)
        --iff we want to keep the line
        if not linefilter(line) then return nil end
        return line
    end
end

only_primes = function(line)
    return line:match(", a prime")
end

--use as:
for line in filtered_lines(input,only_primes) do
    ...
end
0

Here's an approach that works within TeX, using listofitems and readarray to read the file, sort into an array, and screen the array.

\documentclass{article}
\begin{filecontents*}[overwrite]{data.txt}
1, not a prime
2, a prime
3, a prime
4, not a prime
5, a prime
6, not a prime
7, a prime
8, not a prime
9, not a prime
\end{filecontents*}
\usepackage{readarray}
%\usepackage{listofitems}% INCLUDED WITH readarray
\newcommand\findrecords[3]{%
  \def\CMP{#1}%
  \def#3{}%
  \foreachitem\z\in#2[]{%
    \itemtomacro#2[\zcnt,2]\tmp%
    \ifx\tmp\CMP
      \if\relax#3\relax\else\edef#3{#3,}\fi%
      \edef#3{#3#2[\zcnt,1]}%
    \fi
  }%
}
\begin{document}
\readarraysepchar{\\}
\readdef{data.txt}\mydatadef% READ \\ SEPARATED RECORDS INTO \mydatadef
\setsepchar{\\/,}
\ignoreemptyitems
\readlist*\mydata{\mydatadef}% PLACE DATA INTO \mydata ARRAY

\findrecords{a prime}{\mydata}{\APlist}
Primes: \APlist

\findrecords{not a prime}{\mydata}{\NAPlist}
Not primes: \NAPlist
\end{document}

enter image description here

You must log in to answer this question.

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