Lua学习笔记-9.3章-协同用做迭代器

例子:打印一个数组元素的所有的排列。

直接写这样一个迭代函数来完成这个任务并不容易,但是写一个生成所有排列的递归函数并不难。思路:将数组中的每一个元素放到最后,依次递归生成所有剩余元素的排列。

普通的loop实现代码:

function printResult(a)
    for i = 1, #a do
        io.write(a[i], ' ')
    end 
    io.write('\n')
end
 
function permgen(a, n)                                                                                                             
    n = n or #a
    if n <= 1 then
        printResult(a)
    else
        for i = 1, n do
            a[n], a[i] = a[i], a[n]--交换a[i]和a[n]
            permgen(a, n-1)
            a[n], a[i] = a[i], a[n]
        end 
    end 
end
 
permgen({1,2,3})
Lua学习笔记-9.3章-协同用做迭代器_第1张图片
迭代器实现,注意比较下代码的改变的部分:

第一步:将permgen中的printResult修改为yield函数

第二步:定义一个迭代工厂,修改生成器在生成器内创建迭代函数,并使生成器运行在一个协同程序内。迭代函数负责请求协同产生下一个可能的排列。

--定义迭代工厂,修改生成器在生成器内创建迭代函数,使生成器运行在一个协同程序内。迭代函数负责请求协同产生的下一个可能的排列。      
function permutations(a)--迭代工厂
    local co = coroutine.create(function () permgen(a) end)--生成器运行于协同程序内                                                                    
    return function ()--迭代器
        local code, res = coroutine.resume(co)--在迭代器内resume,以产生下一个的permutations
        return res 
    end 
end  

这样我们就可以使用for循环来打印出一个数组的所有排列情况了。

for p in permutations({"a", "b", "c"}) do
    printResult(p)
end

完整代码:

function printResult(a)
    for i = 1, #a do
        io.write(a[i], ' ')
    end 
    io.write('\n')
end  
        
function permgen(a, n)
    n = n or #a
    if n <= 1 then
       coroutine.yield(a)--注意此处的差别,上述例子是printResult(a)
    else
        for i = 1, n do
            a[n], a[i] = a[i], a[n]
            permgen(a, n-1)
            a[n], a[i] = a[i], a[n]
        end 
    end 
end  
        
function permutations(a)--注意此处的代码
    local co = coroutine.create(function () permgen(a) end)                                                                        
    return function ()
        local code, res = coroutine.resume(co)
        return res 
    end 
end  
        
for p in permutations({"a", "b", "c"}) do
    printResult(p)
end
运行结果如下:

Lua学习笔记-9.3章-协同用做迭代器_第2张图片

permutations 函数使用了一个Lua中的常规模式,将在函数中去resume一个对应的coroutine进行封装。Lua对这种模式提供了一个函数coroutine.wap 。跟create 一样,wrap 创建一个新的coroutine ,但是并不返回给coroutine,而是返回一个函数,调用这个函数,对应的coroutine就被唤醒去运行。跟原来的resume 不同的是,该函数不会返回errcode作为第一个返回值,一旦有error发生,就退出了(类似C语言的assert)。使用wrap, permutations可以如下实现:

function permutations (a)
    return coroutine.wrap(function () permgen(a) end)
end

wrap 比create 跟简单,它实在的返回了我们最需要的东西:一个可以唤醒对应coroutine的函数。 但是不够灵活。没有办法去检查wrap 创建的coroutine的status, 也不能检查runtime-error(没有返回errcode,而是直接assert)。


你可能感兴趣的:(Lua学习笔记-9.3章-协同用做迭代器)