To put it simple, I want to go through every single object in an array in a way that is random every time.
I've found out that by using this method:
local array = something:GetChildren() for i=1, #array do array[i] --do something end
it would go through every single object of the array by their time of creation which would be the same every time the code is run. So, I'm asking you what would be the easiest way to make it happen randomly.
So far I've thought of
local i = math.random(1,#array)
but it would be too messy, because you would have to keep track of objects that' already have gone through.
Thankyou in advance!
There are evidently many solutions to this problem, but I'll just share the first (and in my opinion, the simplest) that comes to mind.
You most likely don't want to change the state of the array whilst listing random indices, so you probably want some sort of buffer to temporarily represent the array. Then, a new table to store the new random configuration of the array.
local function randomSortArray(array) -- A buffer that is a direct clone of the array for temporary use local buffer = {} for i = 1, #array do buffer[i] = array[i] end -- The new array that represents a random configuration of the buffer array local newArray = {} while (#buffer > 0) do -- Remove the randomly chosen index from the buffer to ensure original values each iteration newArray[#newArray+1] = table.remove(buffer, math.random(#buffer)) end -- Teturn the random configuration return newArray end
Create a clone of the original array (a buffer)
buffer = {}
Copy all elements from array into the buffer
for i = 1, #array do buffer[i] = array[i]; end
Create a new empty table to store the random order of the array
newArray = {}
Traverse the buffer, choose a random index, and insert that into the new array
newArray[#newArray+1] = table.remove(buffer, math.random(#buffer))
Return the new array
Notice that, while inserting the next random index to the new array, we're also removing it from the buffer. This is so that we update the probability according to the size of the array, while retaining it's array structure. I hope this helped. If you have any questions, just leave a comment and I'll get to it.
I would use a temporary permutation array:
local function RandomPermutation(n) -- Initialize the permutation as the array 1...n: local perm = {} for i = 1, n do perm[i] = i end -- A Fisher-Yates shuffle: for i = 1, n-1 do local j = math.random(i, n) perm[i], perm[j] = perm[j], perm[i] end return perm end -- Example: local array = something:GetChildren() local perm = RandomPermutation(#array) for _, i in ipairs(perm) do DoSomething(array[i]) end
You might possibly also do a random shuffle directly reordering the array you want to loop over, instead.
I copied this from the dev forum, but I think you could go:
local array = {"I", "am", "kazeks123", "Me", "is", "cool"} local function Shuffle(t) for i = #t, 2, -1 do local j = Random.new():NextInteger(1, i) t[j], t[i] = t[i], t[j] end end Shuffle(array) for i, v in pairs(array) do print(v) end
(if you want to keep the original table maybe make the shuffled table a duplicate of it)
Hope this helps
Don't re-invent the wheel -- shuffling a list is a common problem. It's a little surprising Lua doesn't have an in-built solution. Then again, there are many things Lua doesn't have because it's not a very good language.
From here: https://gist.github.com/Uradamus/10323382
function shuffle(tbl) for i = #tbl, 2, -1 do local j = math.random(i) tbl[i], tbl[j] = tbl[j], tbl[i] end return tbl end
This should shuffle a table in-place. Copy the table before passing it if you need to retain order.
function copyTable(tbl) newTable = {} for i, v in pairs(tbl) do newTable[i] = v end return newTable end
smh "don't re-invent the wheel" then does that
function shuffleButNotInPlace(oldTable) tbl = {unpack(oldTable)} for i = #tbl, 2, -1 do local j = math.random(i) tbl[i], tbl[j] = tbl[j], tbl[i] end return tbl end