Reputation: 23
I wonder if there is a way to make large nested 'for loops' more compact hence less code.
for a = 1, 10 do
for b = 1, 10 do
for c = 1, 10 do
...
if a == 1 and b == 2 and c == 3 ... y == 4 and z == 5 then
print("test")
end
...
end
end
end
Upvotes: 1
Views: 434
Reputation: 1411
You can write your own iterators in Lua, which could let you express this. The manual explains how they are invoked.
For example, here's a grid
iterator-generator that lets you iterate over a "grid" in lexicographic order:
-- Lua 5.1's "unpack" was renamed to "table.unpack" in Lua 5.2
table.unpack = table.unpack or unpack
function iterator(t, i)
local n = i + 1
local r = {}
local p = 1
for k = #t, 1, -1 do
p = p * t[k]
-- or, "c = i % t[k] // 1" in Lua 5.3
local c = i % t[k]
r[k] = 1 + c
-- or, "i = i // t[k]" in Lua 5.3
i = (i - c) // t[k]
end
if n > p then
return nil, table.unpack(r)
end
return n, table.unpack(r)
end
function grid(...)
return iterator, {...}, 0
end
You could use it like
for i, a, b, c in grid(10, 10, 10) do
if a ^ 2 + b ^ 2 == c ^ 2 then
print(string.format("%d^2 + %d^2 = %d^2", a, b, c))
end
end
--> 3^2 + 4^2 = 5^2
--> 4^2 + 3^2 = 5^2
--> 6^2 + 8^2 = 10^2
--> 8^2 + 6^2 = 10^2
Because a simple for i = 1, 10 do
loop is provided by Lua itself, the loop-accounting will be significantly faster than using an iterator like this. However, the difference that this makes diminishes the more work happens per iteration. If you only do a few simple lines of code in each iteration, the performance overhead of iterator
being called repeatedly (which also constructs tables!) will far outweigh the actual work being done in the loop. But if you only iterate a few times, and each iteration does a lot of work, it won't end up mattering.
Upvotes: 2
Reputation: 5564
One alternative is to store all of the counter variables in a single table. Then you can have a single loop which calls a function which adjusts the counters one at a time.
local N_COUNTERS = 8
-- Increment the counters by one step. If all counters are at 10, return true.
local function uptick(counters)
for i = #counters, 1, -1 do
local n = counters[i]
if n < 10 then
counters[i] = n + 1
return false
end
counters[i] = 1
end
return true
end
-- Look at all counters and return a boolean.
local function doCheck(counters)
for i, n in ipairs(counters) do
if i ~= n then
return false
end
end
return true
end
local counters = {}
for i = 1, N_COUNTERS do
counters[i] = 1
end
repeat
if doCheck(counters) then
print('test')
end
until uptick(counters)
I set N_COUNTERS
to 8, because that's the largest value that doesn't take a very long time to run on my machine. I don't know if there's anything you can do to speed this up.
Upvotes: 0
Reputation: 28994
Loops of any kind repeat their body until a certain condition is met.
It already is the simplest way to tell your computer to execute code multiple times.
Hence there is no simplification.
In your example you could simply print("test")
once, as your condition is most likely only met once in 10^24 iterations.
Upvotes: 1