Accessing table entries with iterators

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Accessing table entries with iterators

Henderson, Michael D
The PIL says, "With proper iterators, we can traverse almost anything,
and do it in a readable fashion." I guess that I'm just not
understanding iterators.

If I have an entry like the following

entry = { timestamp = "2006/01/16 132155"
        , { "cpu" , 42.3  }
        , { "fan" , 5823  }
        , { "aaa" , "bbb" }
        };

How would I iterate through the table to print out something like the
following?

        timestamp is '2006/01/16 132155'
        resource #1
                type is 'cpu'
                value is (number) 42.3
        resource #2
                type is 'fan'
                value is (integer) 5823
        resource #3
                type is 'aaa'
                value is (string) 'bbb'

If I use pairs(entry), I don't get the resources in the order that they
were created.
        1
        2
        3
        timestamp

I can get pretty close by using the iterator from PIL 7.1:

        function list_iter (t)
          local i = 0
          local n = table.getn(t)
          return function ()
                   i = i + 1
                   if i <= n then return t[i] end
                 end
        end

        if entry.timestamp then
                print(entry.timestamp)
        end
        for k in list_iter(entry) do
                print(k)
                for kk in pairs(k) do
                        print("\t" .. kk)
                        print("\t\t" .. k[kk])
                end
        end

        2006/01/16 132155
        table: 42f10
                1
                        cpu
                2
                        42.3
        table: 47f20
                1
                        fan
                2
                        5823
        table: 47f70
                1
                        aaa
                2
                        bbb

That's nice, but I want an iterator that throws an error if the
timestamp is missing or the values are missing. And I want to return the
two entries as two entries, not as a table. Would I do that by adding a
check prior to the return t[i] to verify that table.getn(t[i]) is 2? If
so, can I then just return t[i][1], t[i][2]? I guess that if I did that,
it would look like.

        function tbl_iter (t)
          if not t.timestamp then
            error("missing timestamp")
          end;
          local i = 0
          local n = table.getn(t)
          return function ()
           i = i + 1
           if i <= n then
             if table.getn(t[i]) == 2 then
               return t[i][1] , t[i][2]
             else
               error("missing entries")
             end
           end
         end
        end

        if entry.timestamp then
                print(entry.timestamp)
        end

        for k1, k2 in tbl_iter(entry) do
                print("type is " .. k1 .. " value is " .. k2 )
        done

        2006/01/16 132155
        type cpu value 42.3
        type fan value 5823
        type aaa value bbb

That seems to solve my problem. Man, this list is great!

Which leads me to another question. Is there a better way to write this?
This will run only a couple of hundred times a day and always against a
small table (maybe 30 entries), so performance isn't an issue, but I'd
like to make sure that I'm really understanding the right way to do
iterators.

Thanks,
Mike Henderson
Reply | Threaded
Open this post in threaded view
|

Re: Accessing table entries with iterators

Javier Guerra Giraldez
On Monday 16 January 2006 3:59 pm, Henderson, Michael D wrote:

> The PIL says, "With proper iterators, we can traverse almost anything,
> and do it in a readable fashion." I guess that I'm just not
> understanding iterators.
>
> If I have an entry like the following
>
> entry = { timestamp = "2006/01/16 132155"
>         , { "cpu" , 42.3  }
>         , { "fan" , 5823  }
>         , { "aaa" , "bbb" }
>         };
>
.... snip......
>
> Which leads me to another question. Is there a better way to write this?

i like to write coroutine iterators (UNTESTED):

function get_iter (t)
  return coroutine.wrap (function ()
    if not t.timestamp then
      error ("missing timestamp")
    end
    for _, v in ipairs (t) do
      if (type (v) ~= "table" or not (v[1] and v[2])) then
        error ("bad entry")
      end
      coroutine.yield (v[1], v[2])
    end
  end)
end

might be a bit slower than a handcoded state machine, but much easier to read

i wonder why you want the timestamp test in the iterator..., maybe it would be
better in the iterator factory:

function get_iter (t)
  if not t.timestamp then
    error ("missing timestamp")
  end
  return coroutine.wrap (function ()
    for _, v in ipairs (t) do
      if (type (v) ~= "table" or not (v[1] and v[2])) then
        error ("bad entry")
      end
      coroutine.yield (v[1], v[2])
    end
  end)
end


--
Javier

attachment0 (205 bytes) Download Attachment