This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
darkhenmore's profile picture

in pairs gives strange ordering

Started by darkhenmore, 20 June 2013 - 03:40 PM
darkhenmore #1
Posted 20 June 2013 - 05:40 PM
Hello,
I am a bit confused as to the output i get when running this code:


table={
["a"]="1",
["b"]="2",
["c"]="3",
["d"]="4",
["e"]="5"}
for k,v in pairs(table) do
print(v)
end

I would expect the output to be a list going 1 2 3 4 5. But instead i get a list like: 1 3 2 5 4.
I was hoping someone could explain why it does this and also how to prevent it.
Thanks
GopherAtl #2
Posted 20 June 2013 - 05:43 PM
it does this because lua tables are hash maps, which are not ordered. They are only ordered when used as arrays, with ascending, numeric indices. The only way around this in general is to use arrays instead of hash maps.
darkhenmore #3
Posted 20 June 2013 - 05:48 PM
The only way around this in general is to use arrays instead of hash maps.
How do i do that?
GopherAtl #4
Posted 20 June 2013 - 05:58 PM
arrays have numbers as keys, starting with 1 and going up. They can be iterated with iPairs, or just by doing "for i=1,#myArray"

ex…


myArray={"a","b","c","d","e",}
for i=1,#myArray do
print(myArray[i])
end
darkhenmore #5
Posted 20 June 2013 - 06:00 PM
So there is no way to have custom keys and still work through them in order
GopherAtl #6
Posted 20 June 2013 - 06:06 PM
not directly, no. You could build a separate sorted list of values before printing, of course.

like so:

myTable={"foo"=1,"bar"=5,"splat"=27}

--//make an array of the values
valueArray={}
for k,v in pairs(myTable) do
  table.insert(valueArray,v)
end

--//Sort it
table.sort(valueArray)

--print
for i=1,#valueArray do
  print(valueArray[i])
end
theoriginalbit #7
Posted 20 June 2013 - 11:45 PM
As GopherAtl stated it is not directly possible to get the default pairs to work in that way.

However, we can also write a pairs function to do it for us

local function orderedPairs( _t )
  --# make a copy of our table, ONLY the keys
  local keys = {}
  for k,_ in pairs( _t ) do
	keys[#keys+1] = k
  end

  --# sort the keys, now they will be returned in order
  table.sort(keys)

  --# the starting index
  local i = 0

  --# return the function for the generic for loop
  return function()
	--# increment the index
	i = i + 1
	--# return the key and the value from the original table
	return keys[i], _t[keys[i]]
  end
end

And then we use orderedPairs instead of pairs in our loop.

local t = {
  ["a"]="1",
  ["b"]="2",
  ["c"]="3",
  ["d"]="4",
  ["e"]="5"
}

for k,v in orderedPairs(t) do
  print(k,':',v)
end

Doing it this way also solves another problem with pairs, and that is you cannot remove a value as it then fails to get the next key/value pair. Code that breaks

local t = {
  ["a"]="1",
  ["b"]="2",
  ["c"]="3",
  ["d"]="4",
  ["e"]="5"
}

for k,v in pairs(t) do
  t[k] = nil
end
will error with "invalid key to 'next'"

however when we do it with the new pairs

local t = {
  ["a"]="1",
  ["b"]="2",
  ["c"]="3",
  ["d"]="4",
  ["e"]="5"
}

for k,v in orderedPairs(t) do
  t[k] = nil
end
we can successfully nil values in our table.