Jonathan Picazo
Jonathan Picazo

Reputation: 1075

How to shift all elements in a table?

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

Answers (4)

finnw
finnw

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

Deduplicator
Deduplicator

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

hjpotter92
hjpotter92

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

Jonathan Picazo
Jonathan Picazo

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

Related Questions