I often use anonmymous records to build on the go data that will eventually be serialized and returned to be consumed somewhere else. This is very flexible, quick to deal with, etc.
But one thing I'm really missing is the ability to do something like this pseudo code:
{|
SomeData = 3
StartTime = ....
if ProcessedFinished then yield { EndTime = ... }
|}
when I could add a field, or not, based on some conditions.
Is there a solution to have the flexibility of the anonymous record, yet have the ability to make conditions like this? I could do a dictionary, then insert values based on conditions but then I'd have to box all the values as well and it would be messy right away.
What you're after is not possible today, but you can get pretty close like so:
let initialData =
{|
SomeData = 3
StartTime = ....
|}
if ProcessedFinished then
{| initialData with EndTime = ... |}
else
initialData
Of course, to represent this as a return type it's now more involved, as you'll likely need to use SRTP in the signature to account for any type with a SomeData and StartTime member on it. It's perfectly fine if this is just in the body of a routine that then produces another result to return, though.
If you want to represent data that may be optionally available based on a condition, especially if you want it to live outside of a given function, I'd recommend an option for that field instead.
Related
I'm modding a game. I'd like to optimize my code if possible for a frequently called function. The function will look into a dictionary table (consisting of estimated 10-100 entries). I'm considering 2 patterns a) direct reference and b) lookup with ipairs:
PATTERN A
tableA = { ["moduleName.propertyName"] = { some stuff } } -- the key is a string with dot inside, hence the quotation marks
result = tableA["moduleName.propertyName"]
PATTERN B
function lookup(type)
local result
for i, obj in ipairs(tableB) do
if obj.type == "moduleName.propertyName" then
result = obj
break
end
end
return result
end
***
tableB = {
[1] = {
type = "moduleName.propertyName",
... some stuff ...
}
}
result = lookup("moduleName.propertyName")
Which pattern should be faster on average? I'd expect the 'native' referencing to be faster (it is certainly much neater), but maybe this is a silly assumption? I'm able to sort (to some extent) tableB in a order of frequency of the lookups whereas (as I understand it) tableA will have in Lua random internal order by default even if I declare the keys in proper order.
A lookup table will always be faster than searching a table every time.
For 100 elements that's one indexing operation compared to up to 100 loop cycles, iterator calls, conditional statements...
It is questionable though if you would experience a difference in your application with so little elements.
So if you build that data structure for this purpose only, go with a look-up table right away.
If you already have this data structure for other purposes and you just want to look something up once, traverse the table with a loop.
If you have this structure already and you need to look values up more than once, build a look up table for that purpose.
I've been making a game with the LOVE2D game engine, and I've stumbled across an issue. I want to access a variable inside a nested table, but I don't know how.
Here's my code right now:
local roomNum = 1
local rooms = { r1 = { complete = false, name = "Room 1" }
if rooms[roomNum].complete == true then --problematic line
--do stuff
end
If I replace rooms[roomNum].complete with rooms.r1.complete then it works.
Any help would be appreciated!
'http://lua-users.org/wiki/TablesTutorial'
The provided link gives easy to understand examples on tables in Lua, so it may prove a useful resource in the future.
As for the why the replacement code worked, a dictionary is just sets of key/value pairs (kvp) . In examples from other languages, these pairs are normally shown as something like KeyValuePair.
In your case, you are using a variation on how dictionaries are used. As you have seen, you can use numbered indexes like room[1], or you can use a string like room["kitchen"]. It gets interesting when you provide a set of data to initialize the dictionary.
Building off of the provided data, you have the following:
local rooms = { r1 = { complete = false, name = "Room 1" }
r1 is equivalent to using rooms["r1"] without the dataset. In providing the dataset, any "named" Key can be referenced like it is a property of the dictionary (think of classes with public getter/setter). For the named keys of a dataset, you can provide a key as numbers as well.
local rooms = { [1] = { complete = false, name = "Room 1" }
This indexing fits the direction you were headed on providing a room index. So, you could either swap the dataset to use integers instead of r1, r2 and so on, or you could concatenate r and the index numbering. That is pretty much up to you. Keep in mind as you go further down nesting the same rules apply. So, complete could look like rooms[1].complete, rooms["r1" ].complete, or rooms.r1.complete.
I would like to know if there's an internal function in Erlang, similar to the one posted below, that will give me the record field values instead of the record field names.
record_info(fields, RecordName).
A record in Erlang is really a tuple with it's first element being the name of the record. After compilation is done, the record will be seen as a tuple.
If you have this record definition:
-record(name, [field, anotherfield]).
Then you can define a value of that record type like so:
#name{ field = value1, anotherfield = value2 }.
However, the actual representation for this under the hood is this:
{name, value1, value2}.
Note that the field names are actually gone here.
Now, if you want a list of the values for each field in the record, you can use tuple_to_list:
[name, value1, value2] = tuple_to_list(Record).
So, as jj1bdx pointed out, if you want a ; separated string of all the values, you could do something like this:
string:join([lists:flatten(io_lib:format("~p", [T])) || T <- tl(tuple_to_list(Record))], ";").
This last code snippet is stolen directly from jj1bdx.
Record in record_info(fields, Record) -> [Field] cannot be a variable, because it must be fixed at the compile time.
If you need to handle the elements in a key-value structure dynamically, use maps.
Reading the injected comments in the Code Snippet should give enough context.
--| Table |--
QuestData = {
["QuestName"]={
["Quest Descrip"]={8,1686192712},
["Quest Descrip"]={32,1686193248},
["Quest Descrip"]={0,2965579272},
},
}
--| Code Snippet |--
--| gets QuestName then does below |--
if QuestName then
-- (K = QuestName) and (V = the 3 entries below it in the table)
for k,v in pairs(QuestData) do
-- Checks to make sure the external function that obtained the QuestName matches what is in the table before cont
if strlower(k) == strlower(QuestName) then
local index = 0
-- Iterates over the first two pairs - Quest Descrip key and values
for kk,vv in pairs(v) do
index = index + 1
end
-- Iterates over the second two pairs of values
if index == 1 then
for kk,vv in pairs(v) do
-- Sends the 10 digit hash number to the function
Quest:Function(vv[2])
end
end
end
end
end
The issue I'm running into is that Lua will only pick up one of the numbers and ignore the rest. I need all the possible hash numbers regardless of duplicates. The QuestData table ("database") has well over 10,000 entries. I'm not going to go through all of them and remove the duplicates. Besides, the duplicates are there because the same quest can be picked up in more than one location in the game. It's not a duplicate quest but it has a different hash number.
Key is always unique. It is the point of the key, that the key is pointing to unique value and you can't have more keys with same name to point different values. It is by definition by Lua tables.
It is like if you would want to have two variables with same name and different content. It does not make sense ...
The table type implements associative arrays. [...]
Like global variables, table fields evaluate to nil if they are not initialized. Also like global variables, you can assign nil to a table field to delete it. That is not a coincidence: Lua stores global variables in ordinary tables.
Quote from Lua Tables
Hashing in Lua
Based on comments, I update the answer to give some idea about hashing.
You are using hashing usually in low-level languages like C. In Lua, the associative arrays are already hashed somehow in the background, so it will be overkill (especially using SHA or so).
Instead of linked lists commonly used in C, you should just construct more levels of tables to handle collisions (there is nothing "better" in Lua).
And if you want to have it fancy set up some metatables to make it somehow transparent. But from your question, it is really not clear how your data look like and what you really want.
Basically you don't need more than this:
QuestData = {
["QuestName"]={
["Quest Descrip"]={
{8,1686192712},
{32,1686193248},
{0,2965579272},
},
},
}
As Jakuje already mentioned table keys are unique.
But you can store both as a table member like:
QuestData = {
-- "QuestName" must be unique! Of course you can put it into a table member as well
["QuestName"]={
{hash = "Quest Descrip", values = {8,1686192712} },
{hash = "Quest Descrip", values = {32,1686193248} },
{hash = "Quest Descrip", values = {0,2965579272} }
}
}
I'm sure you can organize this in a better way. It looks like a rather confusing concept to me.
You've said you can't "rewrite the database", but the problem is the QuestData table doesn't hold what you think it holds.
Here's your table:
QuestData = {
["QuestName"]={
["Quest Descrip"]={8,1686192712},
["Quest Descrip"]={32,1686193248},
["Quest Descrip"]={0,2965579272},
},
}
But, this is actually like writing...
QuestData["Quest Descrip"] = {8,1686192712}
QuestData["Quest Descrip"] = {32,1686193248}
QuestData["Quest Descrip"] = {0,2965579272}
So the second (and then, third) values overwrite the first. The problem is not that you can't access the table, but that the table doesn't contain the values any more.
You need to find a different way of representing your data.
I need to make a where query from an array where each member of the array is a 'like' operation that is ANDed. Example:
SELECT ... WHERE property like '%something%' AND property like '%somethingelse%' AND ...
It's easy enough to do using the ActiveRecord where function but I'm unsure how to sanitize it first. I obviously can't just create a string and stuff it in the where function, but there doesn't seem to be a way possible using the ?.
Thanks
The easiest way to build your LIKE patterns is string interpolation:
where('property like ?', "%#{str}%")
and if you have all your strings in an array then you can use ActiveRecord's query chaining and inject to build your final query:
a = %w[your strings go here]
q = a.inject(YourModel) { |q, str| q.where('property like ?', "%#{str}%") }
Then you can q.all or q.limit(11) or whatever you need to do to get your final result.
Here's a quick tutorial on how this works; you should review the Active Record Query Interface Guide and the Enumerable documentation as well.
If you had two things (a and b) to match, you could do this:
q = Model.where('p like ?', "%#{a}%").where('p like ?', "%#{b}%")
The where method returns an object that supports all the usual query methods so you can chain calls as M.where(...).where(...)... as needed; the other query methods (such as order, limit, ...) return the same sort of object so you can chain those as well:
M.where(...).limit(11).where(...).order(...)
You have an array of things to LIKE against and you want to apply where to the model class, then apply where to what that returns, then again until you've used up your array. Thing that look like a feedback loop tend to call for inject (AKA reduce from "map-reduce" fame):
inject(initial) {| memo, obj | block } → obj
Combines all elements of enum by applying a binary operation, specified by a block or a symbol that names a method or operator.
If you specify a block, then for each element in enum the block is passed an accumulator value (memo) and the element [...] the result becomes the new value for memo. At the end of the iteration, the final value of memo is the return value for the method.
So inject takes the block's output (which is the return value of where in our case) and feeds that as an input to the next execution of the block. If you have an array and you inject on it:
a = [1, 2, 3]
r = a.inject(init) { |memo, n| memo.m(n) }
then that's the same as this:
r = init.m(1).m(2).m(3)
Or, in pseudocode:
r = init
for n in a
r = r.m(n)
If you're using AR, do something like Model.where(property: your_array) , or Model.where("property in (?)", your_array) This way, everything is sanitized
Let's say your array is model_array, try Array select:
model_array.select{|a|a.property=~/something/ and a.property=~/somethingelse/}
Of course you can use any regex as you like.