ninjacoder
ninjacoder

Reputation: 23

How to make large nested 'for loops' more compact loop? Any workaround?

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

Answers (3)

Curtis Fenner
Curtis Fenner

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

luther
luther

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

Piglet
Piglet

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

Related Questions