Lua - why for loop limit is not calculated dynamically? - for-loop

Ok here's a basic for loop
local a = {"first","second","third","fourth"}
for i=1,#a do
print(i.."th iteration")
a = {"first"}
end
As it is now, the loop executes all 4 iterations.
Shouldn't the for-loop-limit be calculated on the go? If it is calculated dynamically, #a would be 1 at the end of the first iteration and the for loop would break....
Surely that would make more sense?
Or is there any particular reason as to why that is not the case?

The main reason why numerical for loops limits are computed only once is most certainly for performance.
With the current behavior, you can place arbitrary complex expressions in for loops limits without a performance penalty, including function calls. For example:
local prod = 1
for i = computeStartLoop(), computeEndLoop(), computeStep() do
prod = prod * i
end
The above code would be really slow if computeEndLoop and computeStep required to be called at each iteration.
If the standard Lua interpreter and most notably LuaJIT are so fast compared to other scripting languages, it is because a number of Lua features have been designed with performance in mind.
In the rare cases where the single evaluation behavior is undesirable, it is easy to replace the for loop with a generic loop using while end or repeat until.
local prod = 1
local i = computeStartLoop()
while i <= computeEndLoop() do
prod = prod * i
i = i + computeStep()
end

The length is computed once, at the time the for loop is initialized. It is not re-computed each time through the loop - a for loop is for iterating from a starting value to an ending value. If you want the 'loop' to terminate early if the array is re-assigned to, you could write your own looping code:
local a = {"first", "second", "third", "fourth"}
function process_array (fn)
local inner_fn
inner_fn =
function (ii)
if ii <= #a then
fn(ii,a)
inner_fn(1 + ii)
end
end
inner_fn(1, a)
end
process_array(function (ii)
print(ii.."th iteration: "..a[ii])
a = {"first"}
end)

Performance is a good answer but I think it also makes the code easier to understand and less error-prone. Also, that way you can (almost) be sure that a for loop always terminates.
Think about what would happen if you wrote that instead:
local a = {"first","second","third","fourth"}
for i=1,#a do
print(i.."th iteration")
if i > 1 then a = {"first"} end
end
How do you understand for i=1,#a? Is it an equality comparison (stop when i==#a) or an inequality comparison (stop when i>=#a). What would be the result in each case?
You should see the Lua for loop as iteration over a sequence, like the Python idiom using (x)range:
a = ["first", "second", "third", "fourth"]
for i in range(1,len(a)+1):
print(str(i) + "th iteration")
a = ["first"]
If you want to evaluate the condition every time you just use while:
local a = {"first","second","third","fourth"}
local i = 1
while i <= #a do
print(i.."th iteration")
a = {"first"}
i = i + 1
end

Related

Filtering a range in Julia

I have some MWE below. What I want is to have a subsection of a range, interact with the rest of the range, but not itself.
For instance if the range is 1:100, I want to have a for loop that will have each index in 4:6, interact with all values of 1:100 BUT NOT 4:6.
I want to do this using ranges/filters to avoid generating temporary arrays.
In my case the total range is the number of atoms in the system. The sub-range, is the atoms in a specific molecule. I need to do calculations where each atom in a molecule interacts with all other atoms, but not the atoms in the same molecule.
Further
I am trying to avoid using if statements because that messes up parallel codes. Doing this with an if statement would be
for i=4:6
for j = 1:100
if j == 4 || j==5 || j==6
continue
end
println(i, " ", j)
end
end
I have actual indexing in my code, I would never hardcode values like the above... But I want to avoid that if statement.
Trials
The following does what I want, but I now realize that using filter is bad when it comes to memory and the amount used scales linearly with b.
a = 4:6
b = 1:100
for i in a
for j in filter((b) -> !(b in a),b)
print(i, " ", j)
end
end
Is there a way to get the double for loop I want where the outer is a sub-range of the inner, but the inner does not include the outer sub-range and most importantly is fast and does not create alot of memory usage like filter does?
If memory usage is really a concern, consider two for loops using the range components:
systemrange = 1:50
moleculerange = 4:12
for i in systemrange[1]:moleculerange[1]-1
println(i)
end
for i in moleculerange[end]+1:systemrange[end]
println(i)
end
You might be able to do each loop in its own thread.
What about creating a custom iterator?
Note that example below needs some adjustments depending on how you define the exception lists (for example for long list with non continues indices you should use binary search).
struct RangeExcept
start::Int
stop::Int
except::UnitRange{Int}
end
function Base.iterate(it::RangeExcept, (el, stop, except)=(it.except.start > 1 ? it.start : it.except.stop+1, it.stop, it.except))
new_el = el+1
if new_el in except
new_el = except.stop+1
end
el > stop && return nothing
return (el, (new_el, stop,except))
end
Now let us test the code:
julia> for i in RangeExcept(1,10,3:7)
println(i)
end
1
2
8
9
10

Ruby elegant alternative to ++ in nested loops?

Before anything, I have read all the answers of Why doesn't Ruby support i++ or i—? and understood why. Please note that this is not just another discussion topic about whether to have it or not.
What I'm really after is a more elegant solution for the situation that made me wonder and research about ++/-- in Ruby. I've looked up loops, each, each_with_index and things alike but I couldn't find a better solution for this specific situation.
Less talk, more code:
# Does the first request to Zendesk API, fetching *first page* of results
all_tickets = zd_client.tickets.incremental_export(1384974614)
# Initialises counter variable (please don't kill me for this, still learning! :D )
counter = 1
# Loops result pages
loop do
# Loops each ticket on the paged result
all_tickets.all do |ticket, page_number|
# For debug purposes only, I want to see an incremental by each ticket
p "#{counter} P#{page_number} #{ticket.id} - #{ticket.created_at} | #{ticket.subject}"
counter += 1
end
# Fetches next page, if any
all_tickets.next unless all_tickets.last_page?
# Breaks outer loop if last_page?
break if all_tickets.last_page?
end
For now, I need counter for debug purposes only - it's not a big deal at all - but my curiosity typed this question itself: is there a better (more beautiful, more elegant) solution for this? Having a whole line just for counter += 1 seems pretty dull. Just as an example, having "#{counter++}" when printing the string would be much simpler (for readability sake, at least).
I can't simply use .each's index because it's a nested loop, and it would reset at each page (outer loop).
Any thoughts?
BTW: This question has nothing to do with Zendesk API whatsoever. I've just used it to better illustrate my situation.
To me, counter += 1 is a fine way to express incrementing the counter.
You can start your counter at 0 and then get the effect you wanted by writing:
p "#{counter += 1} ..."
But I generally wouldn't recommend this because people do not expect side effects like changing a variable to happen inside string interpolation.
If you are looking for something more elegant, you should make an Enumerator that returns integers one at a time, each time you call next on the enumerator.
nums = Enumerator.new do |y|
c = 0
y << (c += 1) while true
end
nums.next # => 1
nums.next # => 2
nums.next # => 3
Instead of using Enumerator.new in the code above, you could just write:
nums = 1.upto(Float::INFINITY)
As mentioned by B Seven each_with_index will work, but you can keep the page_number, as long all_tickets is a container of tuples as it must be to be working right now.
all_tickets.each_with_index do |ticket, page_number, i|
#stuff
end
Where i is the index. If you have more than ticket and page_number inside each element of all_tickets you continue putting them, just remember that the index is the extra one and shall stay in the end.
Could be I oversimplified your example but you could calculate a counter from your inner and outer range like this.
all_tickets = *(1..10)
inner_limit = all_tickets.size
outer_limit = 5000
1.upto(outer_limit) do |outer_counter|
all_tickets.each_with_index do |ticket, inner_counter|
p [(outer_counter*inner_limit)+inner_counter, outer_counter, inner_counter, ticket]
end
# some conditional to break out, in your case the last_page? method
break if outer_counter > 3
end
all_tickets.each_with_index(1) do |ticket, i|
I'm not sure where page_number is coming from...
See Ruby Docs.

Pseudo-Random number generation in lua. Variable loop issues

Alright, someone must know easier ways to do this than me.
I'm trying to write a random number generator using a fairly common formula.
--Random Number Generator
local X0=os.time()
local A1=710425941047
local B1=813633012810
local M1=711719770602
local X1=(((A1*X0)+B1)%M1)
local X2=(((A1*X1)+B1)%M1) --then I basically take the vaiable X1 and feed
--it back into itself.
print(X2)
local X3=(((A1*X2)+B1)%M1)
print(X3)
local X4=(((A1*X3)+B1)%M1)
print(X4)
local X5=(((A1*X4)+B1)%M1)
print(X5)
local X6=(((A1*X5)+B1)%M1)
print(X6)
local X7=(((A1*X6)+B1)%M1)
print(X7)
Etc Etc.
Does anybody know a faster way to do this?
I would love to be able to fit it into something along the lines of a:
for i=1,Number do
local X[loop count]=(((A1*X[Loop count-1])+B1)%M1)
math.randomseed(X[loop count])
local roll=math.random(1,20)
print("You rolled a "..roll)
end
io.read()
Type of string.
I'm using it to generate random numbers for pieces of track I'm making in a tabletop game.
Example hunk of code:
if trackclass == "S" then
for i=1,S do --Stated earlier that S=25
local roll=math.random(1,5)
local SP=math.random(1,3)
local Count= roll
if Count == 1 then
local Track = "Straightaway"
p(Track.." Of SP "..SP)
else
end
if Count == 2 then
local Track = "Curve"
p(Track.." of SP "..SP)
else
end
if Count == 3 then
local Track = "Hill"
p(Track.." of SP "..SP)
else
end
if Count == 4 then
local Track = "Water"
p(Track.." of SP "..SP)
else
end
if Count == 5 then
local Track = "Jump"
p(Track.." of SP "..SP)
else
end
end
end
Unfortunately this seems to generate a pretty poor set of random number distribution when I use it and I would really like it to work out better. Any possible assistance in fleshing out the variable loop cycle would be greatly appreciated.
Even something like a call so that every time math.random() is called, it adds one to the X[loop count]] so that every generated number is actually a better pseudo-random number distribution.
Please forgive my semi-rambling. My mind is not necessarily thinking in order right now.
Does anybody know a faster way to do this?
Each XN in the expression is always the previous X, so just restructure the code to use the previous X rather than creating new ones:
local X = os.time()
local A1 = 710425941047
local B1 = 813633012810
local M1 = 711719770602
function myrandomseed(val)
X = val
end
function myrandom()
X = (A1 * X + B1) % M1
return X
end
Now you can call myrandom to your heart's content:
for i=1,100 do
print(myrandom())
end
Another way of packaging it, to avoid static scope, would be generating random number generators as closures, which bind to their state variables:
function getrandom(seed)
local X = seed or os.time()
local A1 = 710425941047
local B1 = 813633012810
local M1 = 711719770602
return function()
X = (A1 * X + B1) % M1
return X
end
end
Now you call getrandom to get a random number generator for a given seed:
local rand = getrandom()
for i=1,100 do
print(rand())
end
I would love to be able to fit it into something along the lines of a:
math.randomseed(X[loop count])
local roll=math.random(1,20)
If you're calling randomseed every time you call random, you're not using Lua's (i.e. C's) random number generator at all. You can see why this is true by looking at myrandomseed above. Why are you funneling your numbers through Lua's random in the first place? Why not just use math.random and be done with it.
Just make to sure to call math.randomseed once rather than every time you call math.random and you'll be fine.
I'm using it to generate random numbers for pieces of track I'm making in a tabletop game. Example hunk of code:
When you see tons of nearly identical code, you should refactor it. When you see variables names like foo1, foo2, etc. you're either naming variables poorly or should be using a list. In your case you have a bunch of branches Count == 1, Count == 2, etc. when we could be using a list. For instance, this does the same thing as your code:
local trackTypes = { 'Straightaway', 'Curve', 'Hill', 'Water', 'Jump' }
for i=1,S do
local trackTypeIndex = math.random(1, #trackTypes)
local SP = math.random(1, 3)
p(trackTypes[trackTypeIndex]..' of SP '..SP)
end
Note that you can probably guess what trackTypes is just by reading the variable name. I have no idea what S and SP are. They are probably not good names.

Returning multiple ints and passing them as multiple arguements in Lua

I have a function that takes a variable amount of ints as arguments.
thisFunction(1,1,1,2,2,2,2,3,4,4,7,4,2)
this function was given in a framework and I'd rather not change the code of the function or the .lua it is from. So I want a function that repeats a number for me a certain amount of times so this is less repetitive. Something that could work like this and achieve what was done above
thisFunction(repeatNum(1,3),repeatNum(2,4),3,repeatNum(4,2),7,4,2)
is this possible in Lua? I'm even comfortable with something like this:
thisFunction(repeatNum(1,3,2,4,3,1,4,2,7,1,4,1,2,1))
I think you're stuck with something along the lines of your second proposed solution, i.e.
thisFunction(repeatNum(1,3,2,4,3,1,4,2,7,1,4,1,2,1))
because if you use a function that returns multiple values in the middle of a list, it's adjusted so that it only returns one value. However, at the end of a list, the function does not have its return values adjusted.
You can code repeatNum as follows. It's not optimized and there's no error-checking. This works in Lua 5.1. If you're using 5.2, you'll need to make adjustments.
function repeatNum(...)
local results = {}
local n = #{...}
for i = 1,n,2 do
local val = select(i, ...)
local reps = select(i+1, ...)
for j = 1,reps do
table.insert(results, val)
end
end
return unpack(results)
end
I don't have 5.2 installed on this computer, but I believe the only change you need is to replace unpack with table.unpack.
I realise this question has been answered, but I wondered from a readability point of view if using tables to mark the repeats would be clearer, of course it's probably far less efficient.
function repeatnum(...)
local i = 0
local t = {...}
local tblO = {}
for j,v in ipairs(t) do
if type(v) == 'table' then
for k = 1,v[2] do
i = i + 1
tblO[i] = v[1]
end
else
i = i + 1
tblO[i] = v
end
end
return unpack(tblO)
end
print(repeatnum({1,3},{2,4},3,{4,2},7,4,2))

Determine if two tables have the same set of keys

I'm using Lua tables as sets by placing the value of the set in the table key and 1 as the table value, e.g.
function addToSet(s,...) for _,e in ipairs{...} do s[e]=1 end end
function removeFromSet(s,...) for _,e in ipairs{...} do s[e]=nil end end
local logics = {}
addToSet(logics,true,false,"maybe")
To test if two sets are equal I need to ensure that they have exactly the same keys. What's an efficient way to do this?
Since you asked about efficiency, I'll provide an alternative implementation. Depending on your expected input tables, you might want to avoid the second loop's lookups. It is more efficient if the tables are expected to be the same, it is less efficient if there are differences.
function sameKeys(t1,t2)
local count=0
for k,_ in pairs(t1) do
if t2[k]==nil then return false end
count = count + 1
end
for _ in pairs(t2) do
count = count - 1
end
return count == 0
end
Another version avoids lookups unless they are necessary. This might perform faster in yet another set of use-cases.
function sameKeys(t1,t2)
local count=0
for _ in pairs(t1) do count = count + 1 end
for _ in pairs(t2) do count = count - 1 end
if count ~= 0 then return false end
for k,_ in pairs(t1) do if t2[k]==nil then return false end end
return true
end
EDIT: After some more research and testing, I came to the conclusion that you need to distinguish between Lua and LuaJIT. With Lua, the performance characteristics are dominated by Lua's Parser and therefore by the number of source code tokens. For Lua, this means that Phrogz's version is most likely the faster alternative. For LuaJIT, the picture changes dramatically, as the parser is no longer an issue. For almost all cases the first version I showed is an improvement, the second version is probably best when the tables are very big. I would advise everyone to run their own benchmarks and check which version works best in their environment.
Loop through both tables and make sure that the key has a value in the other. Fail as soon as you find a mismatch, return true if you got through both. For sets of size M and N this is O(M+N) complexity.
function sameKeys(t1,t2)
for k,_ in pairs(t1) do if t2[k]==nil then return false end end
for k,_ in pairs(t2) do if t1[k]==nil then return false end end
return true
end
Seen in action:
local a,b,c,d = {},{},{},{}
addToSet(a,1,2,3)
addToSet(b,3,1,2,3,3,1)
addToSet(c,1,2)
addToSet(d,2,1)
print(sameKeys(a,b)) --> true
print(sameKeys(a,c)) --> false
print(sameKeys(d,c)) --> true
Note testing for t[k]==nil is better than just not t[k] to handle the (unlikely) case that you have set a value of false for the table entry and you want the key to be present in the set.

Resources