Reputation: 1075
I'm trying to think of an easy way to make all elements in a table shift up one. It is for a game I am playing, attempting to switch between all targets in a table!
For example, let's say I'm surrounded by three mooks who want to kill me, so I target all of them and they're added into an array like so:
{
"mook1",
"mook2",
"mook3",
}
What I want the function to do is change all indexes to go up one (or the amount I specify), and the last to go to the beginning, so the end result would be:
{
"mook3",
"mook1",
"mook2",
}
I attempted it on my own with a simple function like this:
local function nextIndex(tbl, amount)
local t = {}
for k,v in ipairs(tbl) do
if k < #tbl then
t[k+amount] = v
else
t[1] = v
end
end
return t
end
It works as long as the amount is set to 1. I'm sure there is a much smarter and more efficient way of doing this. Could anyone take a whack at it please?!
Upvotes: 5
Views: 4481
Reputation: 48629
Here's a true "in-place" version. It does not need to temporarily enlarge the table:
local function reverse(t, i, j)
while i < j do
t[i], t[j] = t[j], t[i]
i, j = i+1, j-1
end
end
local function rotate_inplace(t, d, n)
n = n or #t
d = (d or 1) % n
reverse(t, 1, n)
reverse(t, 1, d)
reverse(t, d+1, n)
end
Upvotes: 1
Reputation: 45664
So, the task is to rotate the last rot items to the front.
I added parameter n to allow overriding of the sequence end as determined by #t.
-- uses t[#t+1]...t[#t+rot%#t] as scratch space
local function rotate_mod(t, rot, n)
n = n or #t
rot = rot % n
if rot == 0 then return t end
for i = n, 1, -1 do
t[i + rot] = t[i]
end
for i = 1, rot do
t[i], t[i + n] = t[i + n]
end
return t
end
Or if you want a new array (just ignore parameter r):
local function rotate_new(t, rot, n, r)
n, r = n or #t, {}
rot = rot % n
for i = 1, rot do
r[i] = t[n - rot + i]
end
for i = rot + 1, n do
r[i] = t[i - rot]
end
return r
end
Upvotes: 1
Reputation: 80639
You can use a function like this:
function wrap( t, l )
for i = 1, l do
table.insert( t, 1, table.remove( t, #t ) )
end
end
You can see a test run on codepad. or, if you're uncomfortable with nesting of function calls;
function wrap( t, l )
for i = 1, l do
table.insert( t, 1, t[#t] )
table.remove( t, #t )
end
end
would work the same way.
Upvotes: 4
Reputation: 1075
I worked a bit more and figured out how to do it. This is the code:
local function nextIndex(tbl, amount)
local t = {}
local i
for k,v in ipairs(tbl) do
i = k + amount
if i <= #tbl then
t[i] = v
else
t[i-#tbl] = v
end
end
return t
end
Is there an easier way to do it though?
Upvotes: 2