CSV Files
A comma-separated values (CSV) file is a text file that uses a comma to separate values. Each line of the file is a data record. Each record consists of one or more fields, separated by commas. In MaSH we can read, process and write to CSV files.
Under the hood MaSH uses the CSV package from The League of Extraordinary Packages. You can read more about the package here.
Reading CSV Files
To read a CSV file we call the read method on the mash.csv object. This returns an instance of the League CSV object.
read
mash.csv.read(File: file) -> League\Csv\Reader
Creates a Reader object.
Parameters
file
A Foldr file object whose content will be parsed as a CSV file.
Natural
set file to mash.file(4, "Sales Records.csv")
set csv to mash.csv.read(file)
printline csv
Standard
file = mash.file(4, "Sales Records.csv")
csv = mash.csv.read(file)
printline(csv)
Output
Reader [
[
"Region",
"Country",
"Item Type",
"Sales Channel",
"Order Priority",
"Order Date",
"Order ID",
"Ship Date",
"Units Sold",
"Unit Price",
"Unit Cost",
"Total Revenue",
"Total Cost",
"Total Profit"
],
[
"Australia and Oceania",
"Tuvalu",
"Baby Food",
"Offline",
"H",
"5/28/2010",
"669165933",
"6/27/2010",
"9925",
"255.28",
"159.42",
"2533654.00",
"1582243.50",
"951410.50"
],
[
"Central America and the Caribbean",
"Grenada",
"Cereal",
"Online",
"C",
"8/22/2012",
"963881480",
"9/15/2012",
"2804",
"205.70",
"117.11",
"576782.80",
"328376.44",
"248406.36"
],
[
"Europe",
"Russia",
"Office Supplies",
"Offline",
"L",
"5/2/2014",
"341417157",
"5/8/2014",
"1779",
"651.21",
"524.96",
"1158502.59",
"933903.84",
"224598.75"
],
[
"Sub-Saharan Africa",
"Sao Tome and Principe",
"Fruits",
"Online",
"C",
"6/20/2014",
"514321792",
"7/5/2014",
"8102",
"9.33",
"6.92",
"75591.66",
"56065.84",
"19525.82"
],
[
"Sub-Saharan Africa",
"Rwanda",
"Office Supplies",
"Offline",
"L",
"2/1/2013",
"115456712",
"2/6/2013",
"5062",
"651.21",
"524.96",
"3296425.02",
"2657347.52",
"639077.50"
],
[
"Australia and Oceania",
"Solomon Islands",
"Baby Food",
"Online",
"C",
"2/4/2015",
"547995746",
"2/21/2015",
"2974",
"255.28",
"159.42",
"759202.72",
"474115.08",
"285087.64"
],
[
"Sub-Saharan Africa",
"Angola",
"Household",
"Offline",
"M",
"4/23/2011",
"135425221",
"4/27/2011",
"4187",
"668.27",
"502.54",
"2798046.49",
"2104134.98",
"693911.51"
],
[
"Sub-Saharan Africa",
"Burkina Faso",
"Vegetables",
"Online",
"H",
"7/17/2012",
"871543967",
"7/27/2012",
"8082",
"154.06",
"90.93",
"1245112.92",
"734896.26",
"510216.66"
],
[
"Sub-Saharan Africa",
"Republic of the Congo",
"Personal Care",
"Offline",
"M",
"7/14/2015",
"770463311",
"8/25/2015",
"6070",
"81.73",
"56.67",
"496101.10",
"343986.90",
"152114.20"
]
]
In the example above you’ll note that the header row appears as the first entry. We can tell the CSV reader to use a specific row as the header using the setHeaderOffset method and passing it the numerical index (usually 0) of the row containing the headers. This will change the reader’s internal data to an array of dictionaries keyed by the headers.
Natural
set file to mash.file(4, "Sales Records.csv")
set csv to mash.csv.read(file)
printline csv
Standard
file = mash.file(4, "Sales Records.csv")
csv = mash.csv.read(file)
printline(csv)
Output
Reader [
{
"Region": "Australia and Oceania",
"Country": "Tuvalu",
"Item Type": "Baby Food",
"Sales Channel": "Offline",
"Order Priority": "H",
"Order Date": "5/28/2010",
"Order ID": "669165933",
"Ship Date": "6/27/2010",
"Units Sold": "9925",
"Unit Price": "255.28",
"Unit Cost": "159.42",
"Total Revenue": "2533654.00",
"Total Cost": "1582243.50",
"Total Profit": "951410.50"
},
{
"Region": "Central America and the Caribbean",
"Country": "Grenada",
"Item Type": "Cereal",
"Sales Channel": "Online",
"Order Priority": "C",
"Order Date": "8/22/2012",
"Order ID": "963881480",
"Ship Date": "9/15/2012",
"Units Sold": "2804",
"Unit Price": "205.70",
"Unit Cost": "117.11",
"Total Revenue": "576782.80",
"Total Cost": "328376.44",
"Total Profit": "248406.36"
},
{
"Region": "Europe",
"Country": "Russia",
"Item Type": "Office Supplies",
"Sales Channel": "Offline",
"Order Priority": "L",
"Order Date": "5/2/2014",
"Order ID": "341417157",
"Ship Date": "5/8/2014",
"Units Sold": "1779",
"Unit Price": "651.21",
"Unit Cost": "524.96",
"Total Revenue": "1158502.59",
"Total Cost": "933903.84",
"Total Profit": "224598.75"
},
{
"Region": "Sub-Saharan Africa",
"Country": "Sao Tome and Principe",
"Item Type": "Fruits",
"Sales Channel": "Online",
"Order Priority": "C",
"Order Date": "6/20/2014",
"Order ID": "514321792",
"Ship Date": "7/5/2014",
"Units Sold": "8102",
"Unit Price": "9.33",
"Unit Cost": "6.92",
"Total Revenue": "75591.66",
"Total Cost": "56065.84",
"Total Profit": "19525.82"
},
{
"Region": "Sub-Saharan Africa",
"Country": "Rwanda",
"Item Type": "Office Supplies",
"Sales Channel": "Offline",
"Order Priority": "L",
"Order Date": "2/1/2013",
"Order ID": "115456712",
"Ship Date": "2/6/2013",
"Units Sold": "5062",
"Unit Price": "651.21",
"Unit Cost": "524.96",
"Total Revenue": "3296425.02",
"Total Cost": "2657347.52",
"Total Profit": "639077.50"
},
{
"Region": "Australia and Oceania",
"Country": "Solomon Islands",
"Item Type": "Baby Food",
"Sales Channel": "Online",
"Order Priority": "C",
"Order Date": "2/4/2015",
"Order ID": "547995746",
"Ship Date": "2/21/2015",
"Units Sold": "2974",
"Unit Price": "255.28",
"Unit Cost": "159.42",
"Total Revenue": "759202.72",
"Total Cost": "474115.08",
"Total Profit": "285087.64"
},
{
"Region": "Sub-Saharan Africa",
"Country": "Angola",
"Item Type": "Household",
"Sales Channel": "Offline",
"Order Priority": "M",
"Order Date": "4/23/2011",
"Order ID": "135425221",
"Ship Date": "4/27/2011",
"Units Sold": "4187",
"Unit Price": "668.27",
"Unit Cost": "502.54",
"Total Revenue": "2798046.49",
"Total Cost": "2104134.98",
"Total Profit": "693911.51"
},
{
"Region": "Sub-Saharan Africa",
"Country": "Burkina Faso",
"Item Type": "Vegetables",
"Sales Channel": "Online",
"Order Priority": "H",
"Order Date": "7/17/2012",
"Order ID": "871543967",
"Ship Date": "7/27/2012",
"Units Sold": "8082",
"Unit Price": "154.06",
"Unit Cost": "90.93",
"Total Revenue": "1245112.92",
"Total Cost": "734896.26",
"Total Profit": "510216.66"
},
{
"Region": "Sub-Saharan Africa",
"Country": "Republic of the Congo",
"Item Type": "Personal Care",
"Sales Channel": "Offline",
"Order Priority": "M",
"Order Date": "7/14/2015",
"Order ID": "770463311",
"Ship Date": "8/25/2015",
"Units Sold": "6070",
"Unit Price": "81.73",
"Unit Cost": "56.67",
"Total Revenue": "496101.10",
"Total Cost": "343986.90",
"Total Profit": "152114.20"
}
]
You can loop through the records contained inside a CSV object just like an array.
Natural
set file to mash.file(4, "Sales Records.csv")
set csv to mash.csv.read(file).setHeaderOffset(0)
# A variable which we'll use to total up the profit from all records
set totalProfit to 0
each csv as record
printline "Item: {{record['Item Type']}} - Profit {{record['Total Profit']}}"
set totalProfit to totalProfit + record["Total Profit"]
end
printline
printline "Total Profit {{ totalProfit }}"
Standard
file = mash.file(4, "Sales Records.csv")
csv = mash.csv.read(file).setHeaderOffset(0)
# A variable which we'll use to total up the profit from all records
totalProfit = 0
each (csv as record) {
printline("Item: {{record['Item Type']}} - Profit {{record['Total Profit']}}")
totalProfit = totalProfit + record["Total Profit"]
}
printline()
printline("Total Profit {{ totalProfit }}")
Output
Item: Baby Food - Profit 951410.50
Item: Cereal - Profit 248406.36
Item: Office Supplies - Profit 224598.75
Item: Fruits - Profit 19525.82
Item: Office Supplies - Profit 639077.50
Item: Baby Food - Profit 285087.64
Item: Household - Profit 693911.51
Item: Vegetables - Profit 510216.66
Item: Personal Care - Profit 152114.20
Total Profit 3724348.94
Creating CSV Files
To create a CSV we call the writer method on the mash.csv object. We can pass in an optional string to create the CSV file from.
writer
mash.csv.writer(string: ?data) -> League\Csv\Writer
Creates a Writer object.
Parameters
data (optional)
A string to create the CSV from.
Natural
set header to ['first name', 'last name', 'email']
set records to [
['grace', 'hopper', '[email protected]'],
['ada', 'lovelace', '[email protected]'],
]
set csv to mash.csv.writer()
csv.insertOne(header)
csv.insertAll(records)
printline csv
Standard
header = ['first name', 'last name', 'email']
records = [
['grace', 'hopper', '[email protected]'],
['ada', 'lovelace', '[email protected]'],
]
csv = mash.csv.writer()
csv.insertOne(header)
csv.insertAll(records)
printline(csv)
Output
"first name","last name",email
grace,hopper,[email protected]
ada,lovelace,[email protected]
Saving CSV files
To save the contents of a Writer simply pass it as the data parameter to File.write.
Natural
set outputFolder to mash.file(8, "csv/output")
set header to ['first name', 'last name', 'email']
set records to [
['grace', 'hopper', '[email protected]'],
['ada', 'lovelace', '[email protected]'],
]
set csv to mash.csv.writer()
csv.insertOne(header)
csv.insertAll(records)
set csvFile to outputFolder.write("New Users.csv", csv)
printline csvFile
Standard
outputFolder = mash.file(8, "csv/output")
header = ['first name', 'last name', 'email']
records = [
['grace', 'hopper', '[email protected]'],
['ada', 'lovelace', '[email protected]'],
]
csv = mash.csv.writer()
csv.insertOne(header)
csv.insertAll(records)
csvFile = outputFolder.write("New Users.csv", csv)
printline(csvFile)
Output
File {
"name": "New Users.csv",
"path": "csv/output/New Users.csv",
"modified": "2022-02-17T19:52:03+00:00",
"size": 91,
"is_dir": false,
"mimetype": "text/x-comma-separated-values",
"hidden": false,
"extra": [],
"share": {
"id": 8,
"name": "Generated Data"
}
}