4

I'm trying to create a function that 'drags' a sequential number of elements to a new location within the array, constrained to the current size of the array. Other items should jiggle round the 'dragged' items.

For example, if my array has 7 elements and I want to drag the middle three...

1, 2, 3, 4, 5, 6, 7  <-- keys
a, b, C, D, E, f, g  <-- values

The uppercase chars are the ones I want to 'drag'. If I drag to start of the array (drag to 1) the array would look like this:

1, 2, 3, 4, 5, 6, 7  <-- keys
C, D, E, a, b, f, g  <-- values

If I drag to position 5 (or above - can't be dragged outside current array size) the array would look like this:

1, 2, 3, 4, 5, 6, 7  <-- keys
a, b, f, g, C, D, E  <-- values

Any idea how I can achieve that using Lua in a non-crufty manner?

3
  • How big are the tables involved? How large are the dragged chains? I can think of two main ways to do this offhand but they scale differently to larger sized tables. Commented Aug 21, 2015 at 2:25
  • small tables and chains for the stuff i want to do, but if others use the code then potentially big tables with big chains. Commented Aug 21, 2015 at 2:45
  • Don't have time to write out an answer at the moment but one of the ideas is basically just get your start index and count table.unpack(t, 1, start) + table.unpack(t, start + count) + table.unpack(t, start, start+count) (with whatever +/- 1 is necessary on those to make it work. Though that requires looping to work. The other is repeated table.remove/table.insert pairs. Commented Aug 21, 2015 at 3:16

2 Answers 2

2

Here is a version using table.move available in Lua 5.3.

It copies the group to be dragged into another table and shifts values up or down to make room for the group.

 function drag(t, src, len, dest)
    local copy = table.move(t, src, src + len - 1, 1, {})

    if src >= dest then
        table.move(t, dest, src - 1, dest + len)
    else 
        table.move(t, src + len, dest + len - 1, src)
    end

    table.move(copy, 1, len, dest, t)
 end
Sign up to request clarification or add additional context in comments.

1 Comment

That works very nicely! Despite the somewhat sparse official documentation, I'm starting to realise table.move() is a very flexible and useful function, especially considering its internal optimisations.
1
function drag(t, src, len, dest)
  if len == 0 then return end
  local left, ctr, start, index, elem = math.min(src, dest), 0, 0
  local rot, size = dest - src, src + dest + len - 2 * left
  repeat
    start, index, elem = start + 1, start, t[left + start]
    repeat
      index = (index + rot) % size
      ctr, t[left + index], elem = ctr + 1, elem, t[left + index]
    until index < start
  until ctr == size
end

for K = 1, 5 do
  local tbl = {'a', 'b', 'C', 'D', 'E', 'f', 'g'}
  drag(tbl, 3, 3, K)
  print(table.concat(tbl))
end

2 Comments

Almost ;) It breaks if src + len > dest, eg: for K = 1, 7 do local tbl = {'a', 'b', 'C', 'D', 'E', 'f', 'g'} drag(tbl, 3, 3, K) print(table.concat(tbl)) end
@Aubergine18 - You are trying to drag selected elements beyond the array ;) An assertion assert(math.max(src, dest) + len - 1 <= #t) should be added if you wish to check this condition.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.