迭代器教程 |
|
for
语句迭代器在 ForTutorial 中有介绍。以下是一些关于编写自定义迭代器的笔记。
我们可以编写自己的迭代器,供 for
语句调用。以下 Lua 伪代码描述了 for
语句如何使用迭代器。
-- Equivalent to "for var1, ���, varn in explist do block end" do local iterator, state, var1 = explist local var2, ... , varn while true do var1, ..., varn = iterator(state, var1) if var1 == nil then break end -- for block code end end
状态和当前键值被传递给迭代器。迭代器返回键的新值和任何其他值,例如迭代器生成的值。如果返回 nil
,则 for
循环终止。
以下迭代器将返回一系列平方值。当我们不返回值(即 n>=state
)时,Lua 返回 nil
,从而终止迭代。请注意,迭代器为给定迭代返回序列中的下一个值。我们使用 state
来保存我们希望执行的迭代次数。
> function square(state,n) if n<state then n=n+1 return n,n*n end end
以下是调用迭代器的 for
语句
> for i,n in square,5,0 do print(i,n) end 1 1 2 4 3 9 4 16 5 25
我们可以将上面的示例包装起来(类似于 pairs()
)并提供一个 squares(nbvals)
迭代器构造函数。例如:
> function squares(nbvals) return square,nbvals,0 end -- iterator,state,initial value
现在我们可以像调用 pairs()
一样调用它
> for i,n in squares(5) do print(i,n) end 1 1 2 4 3 9 4 16 5 25
以下迭代器类似于 ipairs,但允许迭代多个表。
function ipairs(...) local t = {...} local tmp = {...} -- if nothing to iterate over just return a dummy iterator if #tmp==0 then return function() end, nil, nil end local function mult_ipairs_it(t, i) i = i+1 for j=1,#t do local val = t[j][i] if val == nil then return val end tmp[j] = val end return i, unpack(tmp) end return mult_ipairs_it, t, 0 end local t1 = {'a', 'b', 'c', 'd', 'e'} local t2 = {'A', 'B', 'C', 'D', 'E', 'F'} for k,v1,v2 in ipairs(t1, t2) do print(k,v1,v2) end
此迭代器生成其参数的素数因子。它依赖于一个显而易见的事实,即非零整数大于 1 的最小正因子必须是素数。
primdiv = function (n) assert(n ~= 0) if n < 0 then n = -n end local f = function (s,v) -- s not used local p if n == 1 then return end while n%v > 0 and v*v < n do if v == 2 then v = 3 else v = v + 2 end end -- while if n%v == 0 then n = n/v; return v end if v*v > n then p = n n = 1; return p end end -- function return f,nil,2 end -- function for p in primdiv(84) do io.write(p," ") end --> 2 2 3 7
RiciLake 说:我忍不住要重写它
function primdiv(n) assert(n ~= 0) if n < 0 then n = -n end local function f(_, v) if n > 1 then while n%v > 0 do v = v + (v == 2 and 1 or 2) if v*v > n then v = n end end -- while n = n / v return v end -- if end -- function return f,nil,2 end -- function primdiv for p in primdiv(84) do io.write(p," ") end --> 2 2 3 7
GavinWraith 说:这要好得多。但是,我认为使用 function primdiv(n)
等同于美沙酮,用于一级语言瘾君子。
function ipairs(t) local function ipairs_it(t, i) i = i+1 local v = t[i] if v ~= nil then return i,v else return nil end end return ipairs_it, t, 0 end
function ripairs(t) local max = 1 while t[max] ~= nil do max = max + 1 end local function ripairs_it(t, i) i = i-1 local v = t[i] if v ~= nil then return i,v else return nil end end return ripairs_it, t, max end
-- from the end backwards function ripairs(t) local function ripairs_it(t,i) i=i-1 local v=t[i] if v==nil then return v end return i,v end return ripairs_it, t, #t+1 end
-- traversing the whole 'array' function ripairs(t) idx={} for k,v in pairs(t) do if type(k)=="number" then idx[#idx+1]=k end end table.sort(idx) local function ripairs_it(t,_) if #idx==0 then return nil end k=idx[#idx] idx[#idx]=nil return k,t[k] end return ripairs_it, t, nil end t1 = {'a', 'b', nil, 'd', 'e', nil} for k,v in ripairs(t1) do print(k,v) end --> 5 e --> 4 d --> 2 b --> 1 a