Swapping an array while iterating over it does not work

I want to use a for loop in ipairs to go over an array and read its contents, but halfway through I need to swap the array to a different one. For some reason the array does not change until it starts being iterated over again.
I think it will be possible to use a while loop or repeat until loop to do this and have it work correctly, But I have not tried that as it will require a lot of boilerplate, I want to explore how to make this work before writing a bunch of code that may or may not be necessary.

A simplified version of this problem is:

local array={"a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a"}
local newarray={"a","a","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b"}
for o=1,2 do
	for i,letter in ipairs(array) do
		if i==1 and o==1 then
			array=newarray
		end
		print(letter)
	end
	print("done!!!!")
end

this code prints
image
The first for o=1,2 do loop is not necessary for this problem to occur, it is just used to show the array does change for the second time.

You simply just can’t swap an array whilst you’re iterating over it, but you can set up a function to make something similar:

Here’s how you could do it with a for i = n0. n1 loop:

local array={"a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a"}
local newarray={"b","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b"}

local curr_array = array
local totalarrayN = (#array + #newarray) / 2

for i = 1, totalarrayN do
	if i == totalarrayN / 2 + 1 then
		curr_array = newarray
	end
	
	local letter = curr_array[i]
	print(letter)
end

Here’s how you could do it with a for k, v nested in a for i = n0, n1 loop:

local array={"a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a"}
local newarray={"b","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b"}

local curr_array = array

for o = 1, 2 do
	for i, letter in ipairs(curr_array) do
		print(letter)
		
		if i == #curr_array / 2 then
			curr_array = newarray
			break
		end
	end	
end

print("done!!!!")

Output:

02:08:29.818   â–¶ a (x9)  -  Server - Script
02:08:29.822   â–¶ b (x9)  -  Server - Script
02:08:29.824  done!!!!  -  Server - Script

Hopefully these examples help with what you’re trying to accomplish. If not, let us know.

Your answers will definitely work, but they are too rigid for my needs. I think this problem is too complex to explain simply.

We have an array of 16 with the letters o and l distributed randomly but with a 9/10 chance to be a o and 1/10 to be a l
This is the array we itterate over

{"o","o","o","o","o","l","o","o","o","o","o","o","l","o","o","o"}

Starting at place 1, it checks that it is not “v”, seeing it is a “o”, it saves it and calls a function to get the length of “o” in a row, in this case 5
another function has the task of changing all the “o” s to “v” s, it does so for

{"v","v","v","v","v","l","o","o","o","o","o","o","l","o","o","o"}

then we want to input this array into the itterator, so that place two, which now is a “v” wont get selected and go through the round again with a length of 4 (as it starts at place 2) and set the “v” s back to “v” s
This is where the aforementioned problem is. I get the array that has correctly placed “v” s and need to put it back into the itterator so that it will skip the places now “v”. instead of going through all the functions again for places 2,3,4,5, it will skip to place 6.

I know that I am not the greatest at explaining, so ask as many questions as you want!
If it helps to make it clear, here is the main function

I only explained above in context of a 1 dimensional array, but the actual code uses a 2 dimentional array, so that is why there is zsize and xsize.

game.ReplicatedStorage.GiveToRender.OnClientEvent:Connect(function(ToRender,BottomPosX,BottomPosZ,PartSize)
	local count=0
	local partsposition=1
	for i,chunkcolumn in ipairs(ToRender) do
		for o,chunk in ipairs(chunkcolumn) do
			local unzippedchunk=http:JSONDecode(chunk)--Uncompresses compressed table for
			for p,column in ipairs(unzippedchunk) do
				for a,part in ipairs(column) do
					if part=="v" then continue end
					count+=1
					if count%10==0 then task.wait() end
					local zsize=getzsize(ToRender,i,o,p,a,part)
					local xsize=getxsize(ToRender,i,o,p,a,part,zsize)
					ToRender=updatemap(ToRender,i,o,p,a,xsize,zsize)--Attempting to change the arrays
					chunkcolumn=ToRender[i]--Attempting to change the arrays
					chunk=chunkcolumn[o]--Attempting to change the arrays
					unzippedchunk=http:JSONDecode(chunk)
					column=unzippedchunk[p]--Attempting to change the arrays
					part=column[a]
					makepart(partsposition,xsize,zsize,part,i,o,p,a,BottomPosX,BottomPosZ,PartSize)
					partsposition+=1
				end
			end
		end
	end
	print(count)
end)

All said above, works in context of this code, the only problem is that setting say, torender to the new array with “v” s does not update it.

It may be necessary to use a manual iterator via a while or repeat until loop, but I want to hear your input first.

Ooh, it sounds like you’re wanting a function to basically re-iterate with the modified array after making the changes to the current array.

If I’m understanding it correctly, you want a function that would read the current key’s value (we’ll call the key’s value a) while it iterates through the array:

local array = {"o","o","o","o","o","l","o","o","o","o","o","o","l","o","o","o"}

for _, letter in array do
    if letter ~= "v" then
        -- do something
    end
end

If a doesn’t match a certain value, (we’ll call it b) then you want it to also check if the other values behind the current key value matches a like so?:

-- this is not the official code, but just for sake of example and simplicity:
local array = {"o","o","o","o","o","l","o","o","o","o","o","o","l","o","o","o"}

for i, letter in ipairs(array) do
    if letter ~= "v" then
        array[i] = "v"

        for j = i, #array do
            if array[j] == letter then
                array[j] = "v"
            else
                break
            end
        end
    end
end

Then afterward, you would want it to continue with the newly modified array. Is this all correct?

Yes this is correct, but your code works changing the array, even a different version more accurate to the original code still swaps the arrays.

local array = {"o","o","o","o","o","l","o","o","o","o","o","o","l","o","o","o"}

local function changeletters(array,letter,startpos)
	for j = startpos+1, #array do
		if array[j] == letter then
			array[j] = "v"
		else
			break
		end
	end
	return array
end

for i, letter in ipairs(array) do
	print(i)
	if letter ~= "v" then
		print("a")
		array[i] = "v"

		array=changeletters(array,letter,i)
	end
end

image
what you are doing is what I want to do yes.

Well, again, you simply can’t swap an array while iterating over it, since it’s going to use that array as a static value. You’d have to make a function to recreate that same exact thing. I think it would be best if you used a for i = n0. n1 loop so you can control how it continues in the array better, which would be a workaround for allowing you to swap out an array… Or, well, using the modified array.

local values = string.split("012", "")
local arrayToIterate = {} -- we're going to use this to generate an array of numbers

local function array_changeAtoB(array, valueToReplace, replacement)
	local currPos = 1 -- where we *should* be currently at
	
	for i = 1, #array do
		if i ~= currPos then continue end -- tell the loop to skip if i doesn't correlate to currPos
		
		local v1 = array[i]

		if v1 == valueToReplace then
			array[i] = replacement
			
			for j = i + 1, #array do -- do another loop to check if the values behind it match with it's value
				local v2 = array[j]
				if v2 == v1 then
					array[j] = replacement
				else
					currPos = j
					break
				end
			end
		else
			currPos += 1
		end
	end
end

-- generating the array for the sake of example:
for i = 1, 16 do
	local chance = math.random(0, 10)
	if chance >= 2 then
		table.insert(arrayToIterate, 2)
	else
		table.insert(arrayToIterate, chance)
	end
end

print("old array:", arrayToIterate)

array_changeAtoB(arrayToIterate, 2, 3)
print("modified array:", arrayToIterate)

Output:

image|135Ă—277 image|234Ă—278



The idea of using a repeat until would’ve also worked, but you’d have to use a yielding function within the script so it does continue. Which you wouldn’t need to yield in this instance, since you want to just swap the array instantly.

Thank you for your input, yes, using:

for i=1,#ToRender do
		local chunkcolumn=ToRender[i]
		for o=1,#chunkcolumn do
			local unzippedchunk=http:JSONDecode(chunkcolumn[o])
			for p=1,#unzippedchunk do
				local column=unzippedchunk[p]
				for a=1,#column do
					local part=column[a]
					if part=="v" then continue end

instead of:

for i,chunkcolumn in ipairs(ToRender) do
		for o,chunk in ipairs(chunkcolumn) do
			local unzippedchunk=http:JSONDecode(chunk)
			for p,column in ipairs(unzippedchunk) do
				for a,part in ipairs(column) do
					if part=="v" then continue end

works.
Thank you for sticking with me so long.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.