Iterate through vars without a index? - variables

I set some vars like this:
local var1Age = 10
local var2Age = 20
local var3Age = 30
Now I want to iterate them with a loop like this:
for i=1, 3 do
if var..i..Age >= 21 then
print("yep")
end
end
I can't change the vars, or create a table instead. Is it possible somehow with this vars?
Edit:
I could do something like this:
if var1Age >= 21 then
print("yep")
end
if var2Age >= 21 then
print("yep")
end
if var3Age >= 21 then
print("yep")
end
But I have ~50 vars like that. That's why I search a way to do it with a loop.
Edit2:
The vars are set by a class I can't change, so I can't change the way the vars are set.
For example I can't set the vars like this:
local varAge = {}
varAge[1] = 10
varAge[2] = 20
varAge[3] = 30
Edit3:
The class saves the vars in a table like this: http://ideone.com/iO4I8N

You could iterate through all local variables via debug.getlocal and filter variables you're interested in by name. http://www.lua.org/pil/23.1.1.html
Here is example on how to use it.
local var1Age = 10
local var2Age = 20
local var3Age = 30
function local_var_value(n)
local a = 1
while true do
local name, value = debug.getlocal(2, a)
if not name then break end
if name == n then
return value
end
a = a + 1
end
end
for i=1, 3 do
local v = local_var_value("var"..i.."Age")
if v and v >= 21 then
print("yep")
end
end

Are you really sure you want to stretch the language usage this far? The use of debug library should be left for advanced use when you cannot do otherwise.
Maybe your programming problem could be solved in a more elegant way using "regular" Lua facilities. To have a sequence of variables indexed by a number, simply use a table as an array:
local varAge = {}
varAge[1] = 10
varAge[2] = 20
varAge[3] = 30
for i=1,#varAge do
if varAge[i] >= 21 then
print("yep")
end
end
EDIT
If you really need to use debug.getlocal and performance is really an issue, you can avoid the potential O(n2) behavior scanning the locals only once and storing their values in a table:
local var1Age = 10
local var2Age = 20
local var3Age = 30
local function GetLocalVars( level )
local result = {}
for i = 1, math.huge do
local name, value = debug.getlocal( level, i )
if not name then break end
result[ name ] = value
end
return result
end
local local_vars = GetLocalVars( 2 )
for i = 1, 3 do
local name = "var"..i.."Age"
local v = local_vars[ name ]
if v and v >= 21 then
print("yep")
end
end

Based on the sample code you provided from your comment here, You should be able to iterate through your data structure without ever needing to use debug.getlocal.
local vars = varcount(DTClass)
for i = 1, vars do
local vari = "var" .. i
local variAge = DTClass[vari.."Age"]
if variAge and variAge >= 21 then
print(DTClass[vari.."Weight"])
end
end
This should work whether DTClass is a table or a userdata assuming it provides a suitable __index. Of course you need some way to determine total elements in DTClass. Just implement the varcount function to do this.
If DTClass is a table, varcount can be as simple as return #DTClass / var_fields.

Related

How to Optimize an Overuse of If Statements in Roblox Studio

The goal of this code is to spawn a ball "GlowyBall" in 1 of 5 preset locations randomly. This script activates when a player hits a button. The ball also needs to spawn as 1 of 3 colors randomly. The code works for the most part, but I am struggling when it comes to making this code optimized. I don't know which datatype I should or even can use to replace these if statements. I am just trying to learn different avenues that can be taken. The reason this code needs to be optimized is that it could be used thousands of times per minute, and I don't want the game to be held back by the code.
...
-- Says that there will be 3 colors
local ColorRange = 3
-- Says that there will be 5 spawn locations
local range = 5
-- Makes the code run continuously
while true do
local ColorNumber = math.random(1, ColorRange)
local Number = math.random(1, range)
-- Chooses the random color
if ColorNumber == 1 then
game.ServerStorage.GlowyBallsSideA.GlowyBallGroup1.Glowyball1.Color = Color3.new(1, 0, 0)
end
if ColorNumber == 2 then
game.ServerStorage.GlowyBallsSideA.GlowyBallGroup1.Glowyball2.Color = Color3.new(0, 1, 0)
end
if ColorNumber == 3 then
game.ServerStorage.GlowyBallsSideA.GlowyBallGroup1.Glowyball3.Color = Color3.new(0, 0, 1)
end
-- Chooses which ball will get cloned
if Number == 1 then
ClonePart = game.ServerStorage.GlowyBallsSideA.GlowyBallGroup1.Glowyball1
end
if Number == 2 then
ClonePart = game.ServerStorage.GlowyBallsSideA.GlowyBallGroup1.Glowyball2
end
if Number == 3 then
ClonePart = game.ServerStorage.GlowyBallsSideA.GlowyBallGroup1.Glowyball3
end
if Number == 4 then
ClonePart = game.ServerStorage.GlowyBallsSideA.GlowyBallGroup1.Glowyball4
end
if Number == 5 then
ClonePart = game.ServerStorage.GlowyBallsSideA.GlowyBallGroup1.Glowyball5
end
wait(.6)
local Clone = ClonePart:Clone()
script.Parent.ClickDetector.MouseClick:connect(function()
Clone.Parent = game.Workspace
Clone.Anchored = false
end)
end
...
I am fairly new to programming as a whole so feel free to teach me a few things, thanks.
Instances in Roblox can be accessed in a few different ways; the most common is dot notation (eg. game.Workspace.Part). It's also possible to access instances like items in a table (eg. game["Workspace"]["Part"]). This is useful when accessing an instance with a space in its name, or to add something to the start/end of a string before accessing it.
The if statements for choosing which ball to clone can then be reduced to the following:
-- Chooses which ball will get cloned
ClonePart = game.ServerStorage.GlowyBallsSideA.GlowyBallGroup1["Glowyball" .. Number] -- Add Number to the end of "Glowyball" before accessing it
The same could be done with choosing the random color, as well as substituting multiple if statements for one if-elseif statement could make the code more readable.
-- Chooses the random color
local Glowyball = game.ServerStorage.GlowyBallsSideA.GlowyBallGroup1["Glowyball" .. ColorNumber]
if ColorNumber == 1 then
Glowyball.Color = Color3.new(1, 0, 0)
elseif ColorNumber == 2 then
Glowyball.Color = Color3.new(0, 1, 0)
elseif ColorNumber == 3 then
Glowyball.Color = Color3.new(0, 0, 1)
end
Heliodex did a good job explaining how to simplify finding the instances, but you could take it a step further and remove the if-statements entirely by replacing them with arrays.
Typically, from a general programming standpoint, when you find that you have a lot of very similar if-statements, the solution is to use a switch-statement instead of if-elseif chains. Switch statements allow you to define a bunch of possible cases and when it executes, it will jump specifically to the case that matches. However, neither lua nor luau support switch statements, but we can get the benefit of switch-statements.
Since you are using random numbers already, you can pre-define your colors into an array and have the random number simply pick an index to use...
-- make some colors to pick from
local colors = {
Color3.new(1, 0, 0),
Color3.new(0, 1, 0),
Color3.new(0, 0, 1),
}
-- Set up the list of spawn locations
local locationGroup = game.ServerStorage.GlowyBallsSideA.GlowyBallGroup1
local spawnLocations = {
locationGroup.Glowyball1,
locationGroup.Glowyball2,
locationGroup.Glowyball3,
locationGroup.Glowyball4,
locationGroup.Glowyball5,
}
-- could this be simplified to ...?
-- local spawnLocations = locationGroup:GetChildren()
-- when someone clicks the button, spawn the part
script.Parent.ClickDetector.MouseClick:Connect(function()
-- choose a color and spawn location
local colorNumber = math.random(1, #colors)
local spawnNumber = math.random(1, #spawnLocations)
local clonePart = spawnLocations[spawnNumber]
local color = colors[colorNumber]
-- spawn it
local clone = clonePart:Clone()
clone.Color = color
clone.Parent = game.Workspace
clone.Anchored = false
end)
The advantage of this approach is that you can simply add more colors and spawn locations to those arrays, and the rest of your code will still work.

What the difference between <= and = in cocotb?

It seem that I can use indifferently <= or = to set an input signal value on my design.
Is there a real difference between two ?
dut.button_in = 0
or
dut.button_in <= 0
I have exactly the same output chronogram.
The answer can be found here.
There is no fundamental difference between <= and = except that = can ovewrite the reference and <= is only used for value assignement.
AlexanderSpirin give some examples to illustrate the problem :
#cocotb.test()
def parallel_example(dut):
reset_n = dut.reset
dut.reset = 1 # OK
dut.reset <= 1 # OK hdl-like shortcut for the next one
dut.reset.value = 1 # OK
reset_n <= 1 # OK
reset_n.value = 1 # OK
reset_n = 1 # Doesn't work: reference overwrite
Thanks to Vinay Madupura for the clue.

Possible to store a value in variable in SPSS?

Is is possible in SPSS to store a value in a variable (not a variable created in a data set)?
For example I have a loop for which I want to pass the value 4 to all the locations in the loop that say NumLvl.
NumLvl = 4.
VECTOR A1L(NumLvl-1).
LOOP #i = 1 to NumLvl-1.
COMPUTE A1L(#i) = 0.
IF(att1 = #i) A1L(#i) = 1.
IF(att1 = NumLvl) A1L(#i) = -1.
END LOOP.
EXECUTE.
You can do this using DEFINE / !ENDDEFINE SPSSs Macro Facility, for example:
DEFINE !MyVar () 4 !ENDDEFINE.
You can then use !MyVar as a substitute for 4 wherever in your syntax you wish.
See DEFINE / !ENDDEFINE documentation for further notes.

Name a Table with a Variable in LUA (LÖVE Engine)?

Basically:
I am making a game in the LÖVE Engine where you click to create blocks
Every time you click, a block gets created at your Mouse X and Mouse Y
But, I can only get one block to appear, because I have to name that block (or table) 'object1'
Is there any way to create table after table with increasing values? (like object1{}, object2{}, object3{}, etc... But within the main table, 'created_objects')
But only when clicked, which I suppose rules out the looping part (but if it doesn't please tell me)
Here's my code so far, but it doesn't compile.
function object_create(x, y, id) **--Agruments telling the function where the box should spawn and what the ID of the box is (variable 'obj_count' which increases every time a box is spawned)**
currobj = "obj" .. id **--Gives my currently created object a name**
crob.[currobj] = {} **--Is supposed to create a table for the current object, which holds all of its properties. **
crob.[currobj].body = love.physics.newBody(world, x, y, "dynamic")
crob.[currobj].shape = love.physics.newRectangleShape(30, 30)
crob.[currobj].fixture = love.physics.newFixture(crob.[currobj].body, crob.[currobj].shape, 1) **--The properties**
crob.[currobj].fixture:setRestitution(0.3)
But what should I replace [currobj] with?
Solved
Found what I was looking for. Here's the code if people are wondering:
function block_create(x, y, id) --(the mouse x and y, and the variable that increases)
blocks[id] = {}
blocks[id][1] = love.physics.newBody(world, x, y, "dynamic")
blocks[id][2] = love.physics.newRectangleShape(45, 45)
blocks[id][3] = love.physics.newFixture(blocks[id][1], blocks[id][2])
blocks[id][3]:setRestitution(0.2)
blocks[id][4] = math.random(0, 255) --The Color
blocks[id][5] = math.random(0, 255)
blocks[id][6] = math.random(0, 255)
blockcount = blockcount + 1
i would probably do something like this.
local blocks = {} -- equivalent of your crob table
function create_block(x, y)
local block = funcToCreateBlock() -- whatever code to create the block
table.insert(blocks, block)
return block
end
if you wanted to get a reference to the block you just created with the function, just capture it.
-- gives you the new block, automatically adds it to the list of created blocks
local new_block = create_block(0, 10)
that sticks block objects in your block table and automatically gives each one a numeric index in the table. so if you called create_block() 3 times for 3 different mouse clicks, the blocks table would look like this:
blocks = {
[1] = blockobj1,
[2] = blockobj2,
[3] = blockobj3
}
you could get the second block obj from the blocks table by doing
local block2 = blocks[2]
or you could loop over all the blocks in the table using pairs or ipairs
for idx, block in pairs(blocks) do
-- do something with each block
end
sorry if this doesn't exactly answer your question. but from what you wrote, there didn't seem to be a real reason why you'd need to name the blocks anything specific in the crob table.
If you want those tables to be global, then you can do something like:
sNameOfTable = "NAME"
_G[sNameOfTable] = {1,2}
and then you will have a table variable NAME as depicted here (Codepad).
Otherwise, if you want it to be a child to some other table, something like this would also do:
tTbl = {}
for i = 1, 20 do
local sName = string.format( "NAME%02d", i )
tTbl[sName] = {1,2}
end
for i, v in pairs(tTbl) do
print( i, v )
end
Don't worry about the unsorted output here(Codepad). Lua tables with indexes need not be sorted to be used.

Convert string to pre-defined variable name in Visual Basic?

I'm programming a basic slot machine in Visual basic, and want to use a for loop to randomly choose the image for each slot, display the image in each slot, and change the slotName variable (so I can check later on which symbols are in the slots) for each slot.
The problem I'm finding with a for loop is that the variables and objects for each slot have different names (slot1Name, slot2Name, slot3Name, lblSlot1, lblSlot2, lblSlot3, etc). Is there any way I could have something like:
currentSlotName = "slot" & i & "Name"
This is the code at the moment, this code is repeated (with different variable and object names), for each of the 3 slots, which is pretty inefficient. How can I tidy this code up?
' Randomise numbers and assign images to slots based on random numbers, if the hold isn't on
' Slot 1
If Not held1 Then
slot1Value = Int(Rnd() * numbersGenerated + 0.5)
Select Case slot1Value
Case 0 To 5
lblSlot1.Image = imgBanana
slot1Name = "Banana"
Case 6 To 11
lblSlot1.Image = imgOrange
slot1Name = "Orange"
Case 12 To 16
lblSlot1.Image = imgCherries
slot1Name = "Cherries"
Case 17 To 19
lblSlot1.Image = imgSeven
slot1Name = "Seven"
Case 20
lblSlot1.Image = imgBatman
slot1Name = "Batman"
Case Else
lblSlot1.Text = "Error. slot1value = " & slot1Value
End Select
End If
I have searched around for this, but I'm very new to Visual Basic, and want to keep my code as simple as possible.
Too much to explain. Arrays is what you need to learn next.
http://msdn.microsoft.com/en-us/library/wak0wfyt.aspx