Efficiency of my function with Lua tables - performance

I have a question about the way I put together this piece of Lua code.
Say, there is a function like the one below, containing 200 myTable tables, where the names are ordered alphabetically:
function loadTable(x)
local myTable
if x == "aaron" then myTable = {1,2,3,4,5,6,7,8,9,0}
elseif x == "bobby" then myTable = {1,3,3,4,5,8,7,8,9,1}
elseif x == "cory" then myTable = {1,2,3,3,3,6,7,8,9,2}
elseif x == "devin" then myTable = {1,2,3,4,5,2,3,4,9,0}
...
else
print("table not available")
end
return myTable
end
and now I want to find the table corresponding to x == "zac" (which happens to be somewhere at the end). I use this line of code:
local foundTable = loadTable("zac")
Isnt this like not efficient at all? If it has to find the table at the very end of the function it has to go through all the previous lines of code. Is there some way to code this more efficiently in lua and find the correct table faster? ?

This can become a lot faster by using... a table!
Simply make a table whose keys are the name of the person and the values are the table you want to load, like this:
local tables = {
john = {1,2,3,4,5,6,7,8,9,0},
peter = {1,3,3,4,5,8,7,8,9,1},
william = {1,2,3,3,3,6,7,8,9,2},
victoria = {1,2,3,4,5,2,3,4,9,0}
--...
}
Then, instead of calling loadTable("richard") simply use tables["richard"] or tables.richard if the key is a valid identifier

Related

Powerquery: passing column value to custom function

I'm struggling on passing the column value to a formula. I tried many different combinations but I only have it working when I hard code the column,
(tbl as table, col as list) =>
let
avg = List.Average(col),
sdev = List.StandardDeviation(col)
in
Table.AddColumn(tbl, "newcolname" , each ([column] - avg)/sdev)
I'd like to replace [column] by a variable. In fact, it's the column I use for the average and the standard deviation.
Please any help.
Thank you
This probably does what you want, called as x= fctn(Source,"ColumnA")
Does the calculations using and upon ColumnA from Source table
(tbl as table, col as text) =>
let
avg = List.Average(Table.Column(tbl,col)),
sdev = List.StandardDeviation(Table.Column(tbl,col))
in Table.AddColumn(tbl, "newcolname" , each (Record.Field(_, col) - avg)/sdev)
Potentially you want this. Does the average and std on the list provided (which can come from any table) and does the subsequent calculations on the named column in the table passed over
called as x = fctn(Source,"ColumnNameInSource",SomeSource[SomeColumn])
(tbl as table, cname as text, col as list) =>
let
avg = List.Average(col),
sdev = List.StandardDeviation(col)
in Table.AddColumn(tbl, "newcolname" , each (Record.Field(_, cname) - avg)/sdev)

GLua - Getting the difference between two tables

Disclaimer: This is Glua (Lua used by Garry's Mod)
I just need to compare tables between them and return the difference, like if I was substrating them.
TableOne = {thing = "bob", 89 = 1, 654654 = {"hi"}} --Around 3k items like that
TableTwo = {thing = "bob", 654654 = "hi"} --Same, around 3k
function table.GetDifference(t1, t2)
local diff = {}
for k, dat in pairs(t1) do --Loop through the biggest table
if(!table.HasValue(t2, t1[k])) then --Checking if t2 hasn't the value
table.insert(diff, t1[k]) --Insert the value in the difference table
print(t1[k])
end
end
return diff
end
if table.Count(t1) != table.Count(t2) then --Check if amount is equal, in my use I don't need to check if they are exact.
PrintTable(table.GetDifference(t1, t2)) --Print the difference.
end
My problem being that with only one of difference between the two tables, this returns me more than 200 items. The only item I added was a String. I tried many other functions like this one but they usually cause a stack overflow error because of the table's length.
Your problem is with this line
if(!table.HasValue(t2, t1[k])) then --Checking if t2 hasn't the value
Change it to this:
if(!table.HasValue(t2, k) or t1[k] != t2[k]) then --Checking if t2[k] matches
Right now what is happening is that you're looking at an entry like thing = "bob" and then you're looking to see whether t2 has "bob" as a key. And it doesn't. But neither did t1 so that shouldn't be regarded as a difference.

LINQ Query Variable passed to Another LINQ Query

What is the difference between the query in this post:
Save LINQ Query As Variable To Call Another LINQ Query
var parentLoc = (from a in db.PartsLocations
where a.LocationName == aContainer
select a.ParentLocation);
var locations = (from b in db.PartsLocations
where b.LocationID == parentLoc
select b).ToList();
to the following example from this post.
Dim persVogel = From p In db.People
Where p.LastName = "Vogel"
Select p
Dim persVogelPHVIS = From pp In persVogel
Where pp.Company.Name = "PHVIS"
Select pp
Both of these have declared 2 queries and use the first query variable into second query.
What is the reason to use Single() in the first example but was not used in visualstudiomagazine.com article? Thanks
The two samples are fundamentally different.
First Sample
I think you pasted this one incorrectly...from the referenced question, the query should be:
var parentLoc = (from a in db.PartsLocations
where a.LocationName == aContainer
select a.ParentLocation).Single();
var locations = (from b in db.PartsLocations
where b.LocationID == parentLoc
select b).ToList();
(I am going to assume that LocationID and ParentLocation are typed as int.)
In this sample parentLoc is an int - a single instance of a ParentLocation value, obtained from the PartsLocations table. So what you get is an int.
The second linq statement sources its records also from the PartsLocations table. It uses parentLoc to identify records within that table (e.g. where b.LocationID == parentLoc). What you get at the end is a set of PartsLocations records.
The .Single() call is made because you want to compare the result to LocationID in the second statement, and cannot compare int to IEnumerable<int>.
Second Sample
Dim persVogel = From p In db.People
Where p.LastName = "Vogel"
Select p
Dim persVogelPHVIS = From pp In persVogel
Where pp.Company.Name = "PHVIS"
Select pp
In the second sample, persVogel is a subset of records from the People table (specifically, the subset of people with LastName == "Vogel") - so what you get is a set of People records.
The second linq statement is based on this subset of records (From pp In persVogel) and further filters them down to records where pp.Company.Name = "PHVIS". What you get is still a set of People records.
These two statements could easily be compressed into one single statement:
Dim persVogelPHVIS = From p In db.People
Where p.LastName = "Vogel"
AndAlso p.Company.Name = "PHVIS"
Select p
You will still get a set of People records at the end.

Iterate over table in order of value

Lets say I have a table like so:
{
value = 4
},
{
value = 3
},
{
value = 1
},
{
value = 2
}
and I want to iterate over this and print the value in order so the output is like so:
1
2
3
4
How do I do this, I understand how to use ipairs and pairs, and table.sort, but that only works if using table.insert and the key is valid, I need to be loop over this in order of the value.
I tried a custom function but it simply printed them in the incorrect order.
I have tried:
Creating an index and looping that
Sorting the table (throws error: attempt to perform __lt on table and table)
And a combination of sorts, indexes and other tables that not only didn't work, but also made it very complicated.
I am well and truly stumped.
Sorting the table
This was the right solution.
(throws error: attempt to perform __lt on table and table)
Sounds like you tried to use a < b.
For Lua to be able to sort values, it has to know how to compare them. It knows how to compare numbers and strings, but by default it has idea how to compare two tables. Consider this:
local people = {
{ name = 'fred', age = 43 },
{ name = 'ted', age = 31 },
{ name = 'ned', age = 12 },
}
If I call sort on people, how can Lua know what I intend? I doesn't know what 'age' or 'name' means or which I'd want to use for comparison. I have to tell it.
It's possible to add a metatable to a table which tells Lua what the < operator means for a table, but you can also supply sort with a callback function that tells it how to compare two objects.
You supply sort with a function that receives two values and you return whether the first is "less than" the second, using your knowledge of the tables. In the case of your tables:
table.sort(t, function(a,b) return a.value < b.value end)
for i,entry in ipairs(t) do
print(i,entry.value)
end
If you want to leave the original table unchanged, you could create a custom 'sort by value' iterator like this:
local function valueSort(a,b)
return a.value < b.value;
end
function sortByValue( tbl ) -- use as iterator
-- build new table to sort
local sorted = {};
for i,v in ipairs( tbl ) do sorted[i] = v end;
-- sort new table
table.sort( sorted, valueSort );
-- return iterator
return ipairs( sorted );
end
When sortByValue() is called, it clones tbl to a new sorted table, and then sorts the sorted table. It then hands the sorted table over to ipairs(), and ipairs outputs the iterator to be used by the for loop.
To use:
for i,v in sortByValue( myTable ) do
print(v)
end
While this ensures your original table remains unaltered, it has the downside that each time you do an iteration the iterator has to clone myTable to make a new sorted table, and then table.sort that sorted table.
If performance is vital, you can greatly speed things up by 'caching' the work done by the sortByValue() iterator. Updated code:
local resort, sorted = true;
local function valueSort(a,b)
return a.value < b.value;
end
function sortByValue( tbl ) -- use as iterator
if not sorted then -- rebuild sorted table
sorted = {};
for i,v in ipairs( tbl ) do sorted[i] = v end;
resort = true;
end
if resort then -- sort the 'sorted' table
table.sort( sorted, valueSort );
resort = false;
end
-- return iterator
return ipairs( sorted );
end
Each time you add or remove an element to/from myTable set sorted = nil. This lets the iterator know it needs to rebuild the sorted table (and also re-sort it).
Each time you update a value property within one of the nested tables, set resort = true. This lets the iterator know it has to do a table.sort.
Now, when you use the iterator, it will try and re-use the previous sorted results from the cached sorted table.
If it can't find the sorted table (eg. on first use of the iterator, or because you set sorted = nil to force a rebuild) it will rebuild it. If it sees it needs to resort (eg. on first use, or if the sorted table was rebuilt, or if you set resort = true) then it will resort the sorted table.

Lua - Sorting a table alphabetically

I have a table that is filled with random content that a user enters. I want my users to be able to rapidly search through this table, and one way of facilitating their search is by sorting the table alphabetically. Originally, the table looked something like this:
myTable = {
Zebra = "black and white",
Apple = "I love them!",
Coin = "25cents"
}
I was able to implement a pairsByKeys() function which allowed me to output the tables contents in alphabetical order, but not to store them that way. Because of the way the searching is setup, the table itself needs to be in alphabetical order.
function pairsByKeys (t, f)
local a = {}
for n in pairs(t) do
table.insert(a, n)
end
table.sort(a, f)
local i = 0 -- iterator variable
local iter = function () -- iterator function
i = i + 1
if a[i] == nil then
return nil
else
return a[i], t[a[i]]
end
end
return iter
end
After a time I came to understand (perhaps incorrectly - you tell me) that non-numerically indexed tables cannot be sorted alphabetically. So then I started thinking of ways around that - one way I thought of is sorting the table and then putting each value into a numerically indexed array, something like below:
myTable = {
[1] = { Apple = "I love them!" },
[2] = { Coin = "25cents" },
[3] = { Zebra = "black and white" },
}
In principle, I feel this should work, but for some reason I am having difficulty with it. My table does not appear to be sorting. Here is the function I use, with the above function, to sort the table:
SortFunc = function ()
local newtbl = {}
local t = {}
for title,value in pairsByKeys(myTable) do
newtbl[title] = value
tinsert(t,newtbl[title])
end
myTable = t
end
myTable still does not end up being sorted. Why?
Lua's table can be hybrid. For numerical keys, starting at 1, it uses a vector and for other keys it uses a hash.
For example, {1="foo", 2="bar", 4="hey", my="name"}
1 & 2, will be placed in a vector, 4 & my will be placed in a hashtable. 4 broke the sequence and that's the reason for including it into the hashtable.
For information on how to sort Lua's table take a look here: 19.3 - Sort
Your new table needs consecutive integer keys and needs values themselves to be tables. So you want something on this order:
SortFunc = function (myTable)
local t = {}
for title,value in pairsByKeys(myTable) do
table.insert(t, { title = title, value = value })
end
myTable = t
return myTable
end
This assumes that pairsByKeys does what I think it does...

Resources