devRicher
devRicher

Reputation: 458

Select array element out of bounds on purpose

Assume the following array:

a = {"a", "b", "c"}

Using a[3], I can access c. But how do I make the string "repeat forever" (while it still only has elements)? Example:

a[4] --will return nil, but I need to to return "a", because 4 is 3 (end of array) + 1 (the element I need).

Question:

How would I make a[4] return the same value as a[1], if a[] consists of 3 elements?

Upvotes: 1

Views: 1502

Answers (2)

tonypdmtr
tonypdmtr

Reputation: 3225

This is just a slight variation of Egor Skriptunoff's correct answer because I didn't want the formatting to be lost if left as comment.

In my view, this one makes the table creation a simpler single statement, and clearer as to the intended action. It also uses the same table as meta-table as a minor optimization.

local
function circle(arr)
  function arr.__index(t, k)
    if type(k) == 'number' and #t > 0 then
      return rawget(t, (k-1) % #t + 1)
    end
  end
  return setmetatable(arr,arr)
end

local a = circle {'a', 'b', 'c'}

for j = -10, 10 do print(j, a[j]) end

Upvotes: 0

Egor   Skriptunoff
Egor Skriptunoff

Reputation: 974

You can either make sure that the key you use is within proper range or you move that logic into a's metatable by implementing the __index metamethod. That way you tell Lua what to return when someone accesses an invalid key in your table. See http://lua-users.org/wiki/MetamethodsTutorial

local function circle(arr)
   setmetatable(arr, {__index =
      function(t, k)
         if type(k) == "number" and #t > 0 then
            return rawget(t, (k-1) % #t + 1)
         end
      end
   })
end

local a = {"a", "b", "c"}
circle(a)

for j = -10, 10 do
   print(j, a[j])
end

Upvotes: 4

Related Questions