Doesnt seem to get the reference in lua, but only the value - lua

I am getting Components, which are saved in tables(I use a special system for better memory effiency). Then i give them as parameters in a given function(with the unpack statement(I already checked it isnt the reason)). So far so good, I get the value that is saved in the Table. But if I change it the component in the table doesnt change value. So in short: I want to give the component by reference but I am giving it by value. I thought Lua always gives values stored in tables by reference. Any help would be appreciated. If you need any additional resources just ask :). Thankyou in advance
function pool:run(dt)-- runs all active systems
local sprite = self.img
for i, method in ipairs(self.mPool) do
if method[1] then
--finds entities with required components
local matches = {}
for x=1, #self.ePool do
if band(self.ePool[x][1], method[2]) == method[2] then
matches[#matches+1] = x
end
end
--get components of entities
local components = {}
for x=1, #method[3] do
components[x] = {}
local marker=1
local savePosition = 1
for Eid=1, matches[#matches] do-- Eid = entity id
if Eid == matches[marker] then
components[marker][#components[marker]+1] = self.cPool[method[3][x]][savePosition]
marker = marker +1
end
if self.cBool[method[3][x]][Eid] then
savePosition = savePosition +1
end
end
end
--reorder and run as coroutine or function
if method[5] then
for x=1, #components do
coroutine.wrap(method[4])(matches[x], unpack(components[x]), dt)
end
else
for x=1, #components do
method[4](matches[x], unpack(components[x]), dt)
end
end
end
end
end

The problem is that if you set a variable to the value of table content the value not the reference will be set.

Related

Is there a way to iterate through a lua table continuously?

I am developing a turn-based game and I have a player table of the following structure
players = {
["p1"] = Player(),
["p2"] = Player(),
...
["pn"] = Player()
}
What I wanted to do is iterate through each players in the table (after each player played his round) and get back to the first index ("p1" in this case)
So it should do the following stuff when I run the code
function shift()
-- do stuff to shift the player's turn
print(player.name)
end
shift() -- "p1"
shift() -- "p2"
...
shift() -- "pn"
shift() -- "p1"
-- and so on
local index
function shift()
if not index then index = next(players) end
print(players[index].name)
index = next(players, next)
end
That should do what you want, if I understood the question correctly ;)
EDIT:
As Egor Skriptunoff pointed out in his comment, you can also have the function return the key and use and instead of an if:
local index
function shift()
index = next(players,index)
return index or next(players)
end
Your loop should be something along the lines of:
for k, player in pairs(players) do
player:Player()
end
If you want to recall the the first players function then just follow this with:
players[1]:Player()
Hope this helped!
Edit: To make it endless, just put it in a 'repeat until loop' so it would look something like:
repeat
<for loop across all players>
until <condition>

How to create a table of unique strings in Lua?

I'm trying to create a function that adds unique string to a table. I also wonder how to print the result.
My Code :
local t = {}
function addUniqueString(str)
--what should be here?
end
function printElements()
--what should be here?
end
addUniqueString("apple")
addUniqueString("orange")
addUniqueString("banana")
addUniqueString("apple")
printElements()
The Result I want : (order doesn't matter)
apple
orange
banana
Since the order doesn't matter, you can just add strings as keys to the table:
local t = {}
function addUniqueString(str)
t[str] = true
end
And to list the strings:
function printElements()
for k in pairs(t) do
print(k)
end
end

Optimize 'if else' conditions in rails

I am making an application, part of whose code requires many if .. else conditions:
if #model_name == "Style"
if row.include? ('colors')
colors = row['colors'].split(';')
model.style_colors.concat Color.where('code IN (?)', colors).map {|i| i.id.to_s }
row.delete('colors')
end
if row.include? ('gender') and row.include? ('garments')
#garments = row['garments']
#gender = row['gender']
row.delete('garments')
row.delete('gender')
end
if row.include? ('sports')
#sports = row['sports']
row.delete('sports')
end
if row.include?('decoration_packages')
#decorations_packages = row['decoration_packages']
row.delete('decoration_packages')
end
model.attributes = row.to_hash.merge!(active: FALSE)
else
model.attributes = row.to_hash
end
I need to make objects of row hash to access subclasses, and then delete them from row so it can be saved to a model.
Any idea how I can minimize the use of conditions or optimize it?
There's a few optimisations here...
row.include? ('gender') and row.include? ('garments')
could be implemented as
['gender', 'garments'].all?{|x| row.include?(x)}
#garments = row['garments']
row.delete('garments')
could be implemented as
#garments = row.delete('garments')
You could actually squash a lot of these onto one line:
if row.include? ('sports')
#sports = row['sports']
row.delete('sports')
end
could be
#sports = row.delete('sports') if row.include? ('sports')
Also worth considering:
Do you need to delete the values from 'row'? Could you just retrieve the value?
What are you trying to do here? It looks like you're pulling a hash into instance variables... Which is what ActiveRecord does, basically. Could you just create a model with these attributes and then call it in this style?
Style.new(row)
if #model_name == "Style"
if row.include?('colors')
model.style_colors.concat(
Color.where(code: row.delete('colors').split(';')).pluck(:id).map(&:to_s)
)
end
if row.include?('gender') and row.include?('garments')
#garments = row.delete('garments')
#gender = row.delete('gender')
end
if row.include?('sports')
#sports = row.delete('sports')
end
if row.include?('decoration_packages')
#decorations_packages = row.delete('decoration_packages')
end
model.attributes = row.to_hash.merge!(active: false)
else
model.attributes = row.to_hash
end
I would do something like this with your current code:
if #model_name == "Style"
row_key_set = row.keys.to_set
if row.include? 'colors'
colors = row['colors'].split(';')
color_ids = Color.where(code: colors).pluck(:id)
model.style_colors.concat(color_ids.map(&:to_s))
end
if row_key_set >= Set['gender', 'garments']
#garments = row.delete('garments')
#gender = row.delete('gender')
end
#sports = row.delete('sports')
#decorations_packages = row.delete('decoration_packages')
model.attributes = row.to_hash.merge(active: false)
else
model.attributes = row.to_hash
end
Instead of using Color.where('code IN (?)', colors) you can just use Color.where(code: colors).
Instead of using .map {|i| i.id.to_s } you can use pluck (.pluck(:id)) to get an array of color ids. This also makes for a quicker query since only the ids get fetched from the database instead of the whole records.
I personally like to use sets to check if multiple values are present in another set. For this reason I create the row_key_set variable row.keys.to_set. Now you can easily check certain keys are present on your hash by just checking if the key set is greater or equal than another set (thus being a superset). row_key_set >= Set['gender', 'garments'] With just one check you could leave this out, but if you have multiple checks this might be worth the trouble. I also find code written this way also more readable, but that's just personal peference.
You don't need to check if a key is present on a Hash, the documentation tells us the following:
Deletes the key-value pair and returns the value from hsh whose key is equal to key. If the key is not found, it returns nil.
This means you can leave out the include? check and write the result from the delete directly to the instance variable. If the key is not present nil will be set for the instance variable.
Lastly I would leave out the explanation mark in row.to_hash.merge!(active: false). The version without explanation mark doesn't alter the original array and reduces the chance on accidental side effects. You're saving the variable to model.attributes anyway and toss away the generated array from the to_hash method. It's normally better to use non-altering versions of methods, unless you explicitly want a certain effect to happen.

Trying to get a total - Ruby

I'm trying to get the total cost in one of my field called "upgrade_cost" and store that in a variable called $tuc
def totalUpgradeCost
$e = Experience.all
$tuc = 0
(e.emf_assets).each do |i|
i.upgrade_cost += $tuc
end
return $tuc
end
I'm getting some error undefined local variable or method `e', new to ruby. Anyone help?
I am assuming that emf_assets are associated (via has_many) with an experience. That said I think the following could work for you:
def total_upgrade_cost
total = 0 # use a more descriptive variable names
all_experiences = Experience.all
all_experiences.each do |experience| # iterate over each `experiment`
experience.emf_assets.each do |asset| # load `emf_assets` for each `experiment`
# add the `upgrade_cost` (which might be `nil`) to `total`
total += asset.upgrade_cost.to_i
end
end
total # no need for an explicit `return`
end
Please note that this might work for smaller numbers of experiences and emf_assets, but in a next step performance will benefit from some optimization. But I think that optimization is out of the scope of this question at the moment. You will need to avoid the N+1 query problem and it might makes sense to do the whole calculation in your database.
What is the e in e.emf_assets? If you mean $e, you aren't allowed to drop the $. In Ruby, a $ at the start of a variable name indicates a global variable. If you aren't using $e outside of this function anyway, it would be better to call it simply e, so that it wouldn't be visible outside of the function. Regardless, you're getting an error because $e refers to a global, and e refers to a separate (undefined) local variable.
This is not PHP. $ sign isn't required everywhere. You've used $ with one e and left another empty, that's why the error.
This code should work:
def totalUpgradeCost
e = Experience.all
tuc = 0
e.emf_assets.each do |i|
tuc += i.upgrade_cost
end
return tuc
end
This is doable in shorter way:
def totalUpgradeCost
e = Experience.all
e.emf_assets.inject(0) {|sum, i| sum += i.upgrade_cost}
end

Rails: trying to store particular column value in an array

I am building an application in rails, and I have an items_controller which contains the methods application for create, show, edit, destroy etc.
However, I am trying to create my own method to access all the values in a specific column of my database and I am having greatly difficulty in capturing this data in an array.
I have tried the following ways of capturing the data (where 'quantity' is the column in the database for which I looking for):
#items = Item.find(params[:id])
#items2 = #item.find(params[:quantity])
I have also tried:
#items = Item.find(params[:quantity])
& even:
#items = Item.all
#items2 = #item.find(params[:quantity])
However, none of these methods appear to be working. For what I am doing it is not even essential to
know which quantity column values relate to which row...just getting a list of the column values would suffice.
If any one knows what is wrong here, the help you be very greatly appreciated!
Thanks.
UPDATE:
For clarity I am trying to retrieve all the data for a particular column in my database associated with the items_controller and filter the data for a particular piece of data (in this case the string "7" - as the data is returned from the db as a string when using the Items.all method.
I then want a counter to increase each time the "7" is encountered in the quantity column.
def chartItems
#items = Item.find(params[:id])
#items2 = #items.find(params[:quantity])
#filter = custom_filter_for(#items2)
def custom_filter_for(value)
j=0 # counter initialised at 0
value.each do |x|
if x == "7" # checking for data equal to "7" - the num is retrieved as a string
j = j+1 # increase j counter by 1 whenever "7" is encountered as a quantity
end
return j
end
end
Your find parameter is handled as an id in this case:
#items = Item.find(params[:quantity])
All items are returned which has the id of your quantity parameter. This is clearly not what you want.
You can select Items based on quantity:
#items = Item.find_by_quantity(params[:quantity])
But if you need only the quantities in an array, this is what you are looking for:
#quantities = Items.select(:quantity).map(&:quantity)
Your updated question:
result = Items.find_by_quantity(params[:quantity]).count
In new versions of ActiveRecord, they've added the pluck which does essentially what #Matzi's select and map method does.
To get all item quantities, you could do
#quantities = Item.pluck(:quantity)
Also, I would double check your use of the find_by helpers. I think that find_by_quantity will only give you a single match back (#item, not #items). To get all, I think you really want to use where
#quantities = Item.where(:quantity => params[:quantity])
If you were to use the pluck I mentioned above, I think your filtering step could also be written pretty concisely. That filter is simply counting the number of 7's in the list, right?
#quantities = Item.pluck(:quantity)
#filtered_values = #quantities.select{|q| q == 7}.length
I hope this helps out.

Resources