I would like to build a table in "ascii" format, using the "struct2table" function. When printed into a cell my structure as the following characteristics:
report.COUNTRY.SOURCE.SCENARIO.CATEGORY.ENTITY = YEAR YEAR
Therefore in order to use the "struct2table" function I wrote a script that loops over field names as follow:
function comboloop = loopover(myStruct)
country=fieldnames(myStruct);
for countryidx=1:length(country)
countryname=country{countryidx};
source=fieldnames(myStruct.(countryname))
for sourceidx=1:length(source)
sourcename=source{sourceidx};
scenario=fieldnames(myStruct.(countryname).(sourcename))
for scenarioidx=1:length(scenario)
scenarioname=scenario{scenarioidx};
category=fieldnames(myStruct.(countryname).(sourcename).(scenarioname))
for categoryidx=1:length(category)
categoryname=category{categoryidx};
struct2table(myStruct.(countryname).(sourcename).(scenarioname).(categoryname))
end
end
end
end
end
Then, I have two problem with the output:
The output is printed directly on the command window, therefore how can I get an output as a table (ascii) in the workspace or outside matlab?
When I use table=struct2table(myStruct.(countryname).(sourcename).(scenarioname).(categoryname)) I get the error message "too many output arguments".
How can I append the results of the line category=fieldnames(myStruct.(countryname).(sourcename).(scenarioname))as a row header of the created output?
Any kind of helps or hints is greatly appreciated since I am struggling quiet a lot for this task!
As an example:
country = HUN
countryname = HUN
source = CRF2014
sourcename = CRF2014
scenario = BASEYEAR
scenarioname = BASEYEAR
category = CAT0 CAT1 CAT2 CAT3
categoryname = CAT0 CAT1 CAT2 CAT3
when running the struct2table, for each categoryname I have several gas entities as a column header (CO2, CH4, N2,...) and below I have the attached years (1990, 1991, 1992,...)
Related
local mapSpawnsData = {}
local JSONData = file.Read(filePath) -- read file as json text
mapSpawnsData = util.JSONToTable(JSONData) -- convert JSON to table
print("TABLE:")
PrintTable(mapSpawnsData)
print("TABLE[1]:")
print(tostring(mapSpawnsData[1]))
This is a script for a game called garrysmod. PrintTable() is a function I can call included in the game.
The code snippet I included returns this: (Same output if I remove the tosring())
TABLE:
gm_construct:
1 = -1303.524902 167.472397 -44.081600
2 = 1250.890137 331.746185 -44.081600
3 = 674.012085 223.775604 -32.148102
TABLE[1]:
nil
I expected to get back "gm_construct". What am I missing here?
What you didn't notice is that PrintTable printed gm_construct: first and then 1 = .
That means the table actually contains only gm_construct key with a table with 3 keys.
To be able to always read PrintTable output properly look at the ident. 1 = is tabulated to the right once, this means they are keys of something nested in the table you initially printed.
If this still confuses you, try to run this:
for k,v in pairs(mapSpawnsData) do
print(k, "=", v)
end
This won't print nested content.
To make your code work do mapSpawnsData.gm_construct[1] or mapSpawnsData["gm_construct"][1]
Currently my code have simple tables containing the data needed for each object like this:
infantry = {class = "army", type = "human", power = 2}
cavalry = {class = "panzer", type = "motorized", power = 12}
battleship = {class = "navy", type = "motorized", power = 256}
I use the tables names as identifiers in various functions to have their values processed one by one as a function that is simply called to have access to the values.
Now I want to have this data stored in a spreadsheet (csv file) instead that looks something like this:
Name class type power
Infantry army human 2
Cavalry panzer motorized 12
Battleship navy motorized 256
The spreadsheet will not have more than 50 lines and I want to be able to increase columns in the future.
Tried a couple approaches from similar situation I found here but due to lacking skills I failed to access any values from the nested table. I think this is because I don't fully understand how the tables structure are after reading each line from the csv file to the table and therefore fail to print any values at all.
If there is a way to get the name,class,type,power from the table and use that line just as my old simple tables, I would appreciate having a educational example presented. Another approach could be to declare new tables from the csv that behaves exactly like my old simple tables, line by line from the csv file. I don't know if this is doable.
Using Lua 5.1
You can read the csv file in as a string . i will use a multi line string here to represent the csv.
gmatch with pattern [^\n]+ will return each row of the csv.
gmatch with pattern [^,]+ will return the value of each column from our given row.
if more rows or columns are added or if the columns are moved around we will still reliably convert then information as long as the first row has the header information.
The only column that can not move is the first one the Name column if that is moved it will change the key used to store the row in to the table.
Using gmatch and 2 patterns, [^,]+ and [^\n]+, you can separate the string into each row and column of the csv. Comments in the following code:
local csv = [[
Name,class,type,power
Infantry,army,human,2
Cavalry,panzer,motorized,12
Battleship,navy,motorized,256
]]
local items = {} -- Store our values here
local headers = {} --
local first = true
for line in csv:gmatch("[^\n]+") do
if first then -- this is to handle the first line and capture our headers.
local count = 1
for header in line:gmatch("[^,]+") do
headers[count] = header
count = count + 1
end
first = false -- set first to false to switch off the header block
else
local name
local i = 2 -- We start at 2 because we wont be increment for the header
for field in line:gmatch("[^,]+") do
name = name or field -- check if we know the name of our row
if items[name] then -- if the name is already in the items table then this is a field
items[name][headers[i]] = field -- assign our value at the header in the table with the given name.
i = i + 1
else -- if the name is not in the table we create a new index for it
items[name] = {}
end
end
end
end
Here is how you can load a csv using the I/O library:
-- Example of how to load the csv.
path = "some\\path\\to\\file.csv"
local f = assert(io.open(path))
local csv = f:read("*all")
f:close()
Alternative you can use io.lines(path) which would take the place of csv:gmatch("[^\n]+") in the for loop sections as well.
Here is an example of using the resulting table:
-- print table out
print("items = {")
for name, item in pairs(items) do
print(" " .. name .. " = { ")
for field, value in pairs(item) do
print(" " .. field .. " = ".. value .. ",")
end
print(" },")
end
print("}")
The output:
items = {
Infantry = {
type = human,
class = army,
power = 2,
},
Battleship = {
type = motorized,
class = navy,
power = 256,
},
Cavalry = {
type = motorized,
class = panzer,
power = 12,
},
}
In my problem which I am trying to solve, there is a performance values table:
Staff PerformanceID Date Percentage
--------------------------------------------------
StaffName1 1 2/15/2016 95
StaffName1 2 2/15/2016 95
StaffName1 1 2/22/2016 100
...
StaffName2 1 2/15/2016 100
StaffName2 2 2/15/2016 100
StaffName2 1 2/22/2016 100
And the SQL statement as follows:
SELECT TOP (10)
tbl_Staff.StaffName,
ROUND(AVG(tbl_StaffPerformancesValues.Percentage), 0) AS AverageRating
FROM
tbl_Staff
INNER JOIN
tbl_AcademicTermsStaff ON tbl_Staff.StaffID = tbl_AcademicTermsStaff.StaffID
INNER JOIN
tbl_StaffPerformancesValues ON tbl_AcademicTermsStaff.StaffID = tbl_StaffPerformancesValues.StaffID
WHERE
(tbl_StaffPerformancesValues.Date >= #DateFrom)
AND (tbl_AcademicTermsStaff.SchoolCode = #SchoolCode)
AND (tbl_AcademicTermsStaff.AcademicTermID = #AcademicTermID)
GROUP BY
tbl_Staff.StaffName
ORDER BY
AverageRating DESC, tbl_Staff.StaffName
What I am trying to do is, from a given date, for instance 02-22-2016,
I want to calculate average performance for each staff member.
The code above gives me average without considering the date filter.
Thank you.
Apart from your join conditions and table names which looks quite complex, One simple question, If you want the results for a particular date then why is the need of having
WHERE tbl_StaffPerformancesValues.Date >= #DateFrom
As you said your query is displaying average results but not for a date instance. Change the above line to WHERE tbl_StaffPerformancesValues.Date = #DateFrom.
Correct me if I am wrong.
Thanks for the replies, the code above, as you all say and as it is also expected is correct.
I intended to have a date filter to see the results from the given date until now.
The code
WHERE tbl_StaffPerformancesValues.Date >= #DateFrom
is correct.
The mistake i found from my coding is, in another block i had the following:
Protected Sub TextBoxDateFrom_Text(sender As Object, e As System.EventArgs) Handles TextBoxDate.PreRender, TextBoxDate.TextChanged
Try
Dim strDate As String = Date.Parse(DatesOfWeekISO8601(2016, WeekOfYearISO8601(Date.Today))).AddDays(-7).ToString("dd/MM/yyyy")
If Not IsPostBack Then
TextBoxDate.Text = strDate
End If
SqlDataSourcePerformances.SelectParameters("DateFrom").DefaultValue = Date.Parse(TextBoxDate.Text, CultureInfo.CreateSpecificCulture("id-ID")).AddDays(-7)
GridViewPerformances.DataBind()
Catch ex As Exception
End Try
End Sub
I, unintentionally, applied .AddDays(-7) twice.
I just noticed it and removed the second .AddDays(-7) from my code.
SqlDataSourcePerformances.SelectParameters("DateFrom").DefaultValue = Date.Parse(TextBoxDate.Text, CultureInfo.CreateSpecificCulture("id-ID"))
Because of that mistake, the SQL code was getting the performance values 14 days before until now. So the average was wrong.
Thanks again.
Considering the following MATLAB structure
report.SCENARIO.CAT.GAS = YEARS (n*n double)
I would like to build a table with the field CAT as a row and the field GAS as a column and then fill the corresponding cells with the YEARS. I am currently proceeding as follows:
function loopover(myStruct)
scenario = fiedlnames(myStruct)
for scenarioidx = 1:length(scenario)
scenarioname = scenario{scenarioidx};
category = fieldnames(myStruct.(scenarioname))
row = category
for categoryidx = 1:length(category)
categoryname = category{categoryidx};
gas = fieldnames(myStruct.(scenarioname).(categoryname))
col = gas
end
for gasidx = 1:length(gas)
gasname = gas{gasidx}
allData(2:end) = gas #gas name starting at the second column
allData(2:end,2) = category #category name starting at the second line
allData(row,col) = myStruct.(scenarioname).(categoryname).(gasname) #filling the cells with corresponding years
end
end
When running this small script I just get an error message
Undefined function or variable "allData"
Does anyone know why? Or maybe better, how to proceed to build such a table?
P.S.: I am using MATLAB R2012, therefore I donĀ“t have access to the struct2table or cell2table functions!
I can't find any good documentation about dataset(), so that's why I want to ask you guys, I'll keep the question short:
Can I set headers (column titles) in a dataset, without entering data into the dataset yet? I guess not, so the 2nd part of the question would be:
Can I make a one-row dataset, in which I name the headers, with empty data, and overwrite it later?
Let me show you what I was trying, but did not work:
dmsdb = dataset({ 'John','Name'},{'Amsterdam','City'},{10,'number' });
produces:
Name City number
John Amsterdam 10 --> Headers are good!
Problem is, that when I am going to add more data to the dataset, it expects all strings to be of the same length. So I use cellstr():
dmsdb(1,1:3) = dataset({ cellstr('John'),'Name'},{cellstr('Amsterdam'),'City'},{10,'number' });
Produces:
Var1 Var2 Var3
'John' 'Amsterdam' 10
Where did my headers go? How do I solve this issue, and what is causing this?
You can set up an empty dataset like either
data = dataset({[], 'Name'}, {[], 'City'}, {[], 'number'});
or
data = dataset([], [], [], 'VarNames', {'Name', 'City', 'number'});
Both will give you:
>> data
data =
[empty 0-by-3 dataset]
But we can see that the column names are set by checking
>> get(data, 'VarNames')
ans =
'Name' 'City' 'number'
Now we can add rows to the dataset:
>> data = [data; dataset({'John'}, {'Amsterdam'}, 10, 'VarNames', get(data, 'VarNames'))]
data =
Name City number
'John' 'Amsterdam' 10
You had the basic idea, but just needed to put your string data in cells. This replacement for your first line works:
>> dmsdb = dataset({ {'John'},'Name'},{{'Amsterdam'},'City'},{10,'number' });
dmsdb =
Name City number
'John' 'Amsterdam' 10
The built-in help for dataset() is actually really good at laying out the details of these and other ways of constructing datasets. Also check out the online documentation with examples at:
http://www.mathworks.com/help/toolbox/stats/dataset.html
One of the Mathworks blogs has a nice post too:
http://blogs.mathworks.com/loren/2009/05/20/from-struct-to-dataset/
Good luck!
Here is an example:
%# create dataset with no rows
ds = dataset(cell(0,1),cell(0,1),zeros(0,1));
ds.Properties.VarNames = {'Name', 'City', 'number'};
%# adding one row at a time
for i=1:3
row = {{'John'}, {'Amsterdam'}, 10}; %# construct new row each iteration
ds(i,:) = dataset(row{:});
end
%# adding a batch of rows all at once
rows = {{'Bob';'Alice'}, {'Paris';'Boston'}, [20;30]};
ds(4:5,:) = dataset(rows{:});
The dataset at the end looks like:
>> ds
ds =
Name City number
'John' 'Amsterdam' 10
'John' 'Amsterdam' 10
'John' 'Amsterdam' 10
'Bob' 'Paris' 20
'Alice' 'Boston' 30
Note: if you want to use concatenation instead of indexing, you have to specify the variable names:
vars = {'Name', 'City', 'number'};
ds = [ds ; dataset(rows{:}, 'VarNames',vars)]
I agree, the help for dataset is hard to understand, mainly because there are so many ways to create a dataset and most methods involve a lot of cell arrays. Here are my two favorite ways to do it:
% 1) Create the 3 variables of interest, then make the dataset.
% Make sure they are column vectors!
>> Name = {'John' 'Joe'}'; City = {'Amsterdam' 'NYC'}'; number = [10 1]';
>> dataset(Name, City, number)
ans =
Name City number
'John' 'Amsterdam' 10
'Joe' 'NYC' 1
% 2) More compact than doing 3 separate cell arrays
>> dataset({{'John' 'Amsterdam' 10} 'Name' 'City' 'number'})
ans =
Name City number
'John' 'Amsterdam' [10]