I have an array with 3 elements:
arr = {11, 22, 33}
I want to print all 3 elements, but starting with the 2nd, so the result might be:
22
33
11
Apparently I should have a second for
for this.
Any way to do this in a single for / ipairs
?
I have an array with 3 elements:
arr = {11, 22, 33}
I want to print all 3 elements, but starting with the 2nd, so the result might be:
22
33
11
Apparently I should have a second for
for this.
Any way to do this in a single for / ipairs
?
table.sort(arr, function(a, b)
return a > b
end)
arr[1], arr[2] = arr[2], arr[1]
no need for a for loop
That goes 2, 1, 3, not 2, 3, 1.
mm no
Another solution would be inserting the first element back into the array and removing it:
local Array = {11, 22, 33};
table.insert(Array, Array[1]);
table.remove(Array, 1);
for i = 1, #Array do
print(Array[i]);
end
Here’s another solution, similar to ReturnedTrue’s, except it never removes the first element:
local YOUR_TABLE = {11, 22, 33}
local inext = ipairs{}
local function handleIndex(i, v)
--[[whatever would be in ur loop]]
print(i, v)
end
for i, v in inext, YOUR_TABLE, 1 do
handleIndex(i, v)
end
handleIndex(inext(YOUR_TABLE, 0))
This is based on how ipairs is implemented. It returns a function that takes a table, t, and an index, i, and finds the next index-value pair given that it’s an array. It’s similar to pairs
and its function next
, which is why I called it inext
.
Sorry, i should have been more specific.
The array is not limited to just 3 elements, it can have n elements and I can start with any element other than the first element.
It is a loop that must scan all the elements of the array, regardless of where it starts.
I know I should create a second one for this, but my question is whether I could do this more cleanly.
Could you show an example of your desired result with a longer array.
Thanks for everyone’s ideas. My question was whether I could “save code” to loop between elements of an array, but apparently there is no ready way to do this. In this way I created a solution:
arr = {5, 3, 8, 1, 7, 9, 2}
I want to start with the 3rd element, for example, so it might print:
8, 1, 7, 9, 2, 5, 3
I made this function:
local arr = {5, 3, 8, 1, 7, 9, 2}
local function loopArray(array, starElement)
local startFound
for _, v in ipairs(array) do
if v == starElement then startFound = true end
if startFound then print(v) end
end
for _, v in ipairs(array) do
if v == starElement then break end
print(v)
end
end
loopArray(arr, 8)
Will print:
8
1
7
9
2
5
3
This might be doable with a custom iterator, but it’d get ugly fast. You’re better off with two loops. Quick sample of how bad a solution would look:
local function xpairs(t, start)
local flip = false
return function(t, ind)
local i, v = ind + 1, t[ind + 1]
if v == nil then
i, v = i - #t, t[i - #t]
elseif i == start then
if flip then return end
flip = not flip
end
return i, v
end, t, start - 1
end
local YOUR_TABLE = {11, 22, 33, 44, 55, 66, 77, 88, 99}
for i, v in xpairs(YOUR_TABLE, 4) do
print(i, v)
end
I’d highly advise against using this in production, but here’s the general idea of how it works:
In Lua, for args in f, ...
calls a function with ...
. It keeps getting called with new args based on what it returns. The code in the do
block with be run, with args
set to whatever f returns. pairs
and ipairs
are what we call iterator factories, which means they return an iterator with the relevant args.
We can define our own factory, xpairs
, which will take args that the internal iterator function relies on (like start), and implement behavior to wrap around when it reaches the end, only stopping (done by returning nil) when it reaches the start again.
(flip
is just to allow it to loop past start
the first time and stop the loop on the second time around.)
or this (if you want to use an index… I noticed your solution searches for a value in the list instead. Don’t forget to handle case of value not found)
local function LoopArray(arr, start)
if start == nil then start = 1 end -- make start arg optional
-- type checking
assert(type(arr)=="table", "First arg must be a table")
assert(type(start)=="number", "Start value is not a number")
-- wrap index using modulo
for i=0, #arr-1 do
print( arr[(i+start-1) % #arr+1] )
end
end
This wraps the index around using modulo. It protects against (allows for) start values that are bigger than the array size, but note that a start value of 0 will begin printing on the last entry since 1 is the first.
The above is basically equiv to:
start = (start-1)%#arr+1 -- force start value to be within arr length
local index = nil
for i=1, #arr do
index = i+start-1
if index > #arr then
index = index - #arr
end
print( arr[index] )
end