Sorted Iteration Simple

lua-users home
wiki

A simple approach using metatables to store the keys added in a table that can be sorted and then traversed vis <this>:ipairs() or <this>:spairs();

If one would need to access the table one could add a reference; holding the access functios in a metatable hides these from a normal traversal of the table but not from the lookup; still access is quite fast;

An implemention to view the table by sorted by values would be no problem if one doesn't delete any entries.

--[[

   LUA 5.1 compatible

   

   Sorted Ordered Table

   keys added will also be stored in a metatable

   they can be called via for i,k in <this>:ipairs() do

   where k is they key of <this> sorted by fsort

   the table holding sorted keys is placed outside the metatable, so one cannot reach it except over the functions

   

   variable names inside __index shouldn't be added, if so you must delete these again to access the metavariable

   or change the metavariable names, , except for the 'del' command. thats the reason why one cannot change its value

]]--

function newT( t )

   local mt,_korder = {},{}

   local fsort = function( a,b ) return tostring(a) < tostring(b) end

   local isSorted = true

   -- set methods

   -- index gets only called if the value is not found in the original table

   -- overridden values can be accessed again by deleting the variable over t[key] = nil

   mt.__index = {

      -- traversal of hidden values

      hidden = function() return pairs( mt.__index ) end,

      -- traversal of table ordered: returning index, key

      ipairs = function( self )

         if not isSorted then

            table.sort( _korder,fsort )

            isSorted = true

         end

         return ipairs( _korder )

      end,

      -- traversal of table

      pairs = function( self ) return pairs( self ) end,

      -- traversal of table sorted: returning key,value

      spairs = function( self )

         if not isSorted then

            table.sort( _korder,fsort )

            isSorted = true

         end

         local i = 0

         local function iter( self )

            i = i + 1

            local k = _korder[i]

            if k then

               return k,self[k]

            end

         end

         return iter,self

      end,

      -- to be able to delete entries we must write a delete function

      del = function( self,key )

         -- check if key exists beforestarting the traversal

         if self[key] then

            self[key] = nil

            for i,k in ipairs( _korder ) do

               if k == key then

                  table.remove( _korder,i )

                  return

               end

            end

         end

      end,

   }

   -- set new index handling, is really on new index !!!

   -- setting an non exisitng key to nil will pass here

   mt.__newindex = function( self,k,v )

      if k ~= "del" and v then

         rawset( self,k,v )

         table.insert( _korder,k )

         isSorted = false

      end

   end

   return setmetatable( t or {},mt )

end

-- CHILLCODEĀ™

Testsuit:
t = newT()



t["a"] = "1"

t["ab"] = "2"

t["abc"] = "3"

t["abcd"] = "4"

t["abcde"] = "5"

t[1] = 6

t[2] = 7

t[3] = 8

t[4] = 9

t[5] = 10



print(">> t:pairs()")

for k,v in t:pairs() do

   print( k,v )

end

print(">> t:ipairs()")

for i,k in t:ipairs() do

   print( i,k,t[k] )

end

print(">> t:spairs()")

for i,v in t:spairs() do

   print( i,v )

end

print(">> t:del( 3 )")

t:del( 3 )

print(">> t:del( \"abc\" )")

t:del( "abc" )

print(">> t:spairs()")

for i,v in t:spairs() do

   print( i,v )

end

print(">> t.abc = 11")

t.abc = 11

print(">> t:spairs()")

for i,v in t:spairs() do

   print( i,v )

end

Output:

>> t:pairs()

1       6

2       7

3       8

4       9

a       1

ab      2

abcd    4

abcde   5

5       10

abc     3

>> t:ipairs()

1       1       6

2       2       7

3       3       8

4       4       9

5       5       10

6       a       1

7       ab      2

8       abc     3

9       abcd    4

10      abcde   5

>> t:spairs()

1       6

2       7

3       8

4       9

5       10

a       1

ab      2

abc     3

abcd    4

abcde   5

>> t:del( 3 )

>> t:del( "abc" )

>> t:spairs()

1       6

2       7

4       9

5       10

a       1

ab      2

abcd    4

abcde   5

>> t.abc = 11

>> t:spairs()

1       6

2       7

4       9

5       10

a       1

ab      2

abc     11

abcd    4

abcde   5

Other iterations, including iteration sorted by key


RecentChanges · preferences
edit · history
Last edited June 4, 2007 11:12 pm GMT (diff)