我正在尝试使用Lua中的mapn和zip函数构建一个优雅的转置函数。
mapn和zip如下(来自lua书):
function map(func, array)
local new_array = {}
for i,v in ipairs(array) do
new_array[i] = func(v)
end
return new_array
end
function mapn(func, ...)
local new_array = {}
local i=1
local arg_length = table.getn(arg)
while true do
local arg_list = map(function(arr) return arr[i] end, arg)
if table.getn(arg_list) < arg_length then return new_array end
new_array[i] = func(unpack(arg_list))
i = i+1
end
end
这些工作符合预期。
然后我定义zip并转置为:
function zip(...)
return mapn(function(...) return {...} end,...)
end
function transpose(...)
return zip(unpack(...))
end
现在,转置({{1,2},{3,4},{5,6}})按预期生成{{1,3,5},{2,4,6}}。
但转置({{1,2},{3,4},{5}})不会产生{{1,3,5},{2,4}}。它只产生一行。
如何让它产生我想要的结果?
我决定写一个“不优雅”的功能。似乎没有流畅的方式来使用mapn和朋友。
function transp(L)
local n=#L
local m,M=1e42,0
--Get the beginning and end of resultant transpose list.
for i=1,n do
for k,v in pairs(L[i]) do
if M<k then M=k end
if m>k then m=k end
end
end
local nt={}
for i=m,M do
local rt={}
for j=1,n do
rt[j]=L[j][i]
end
table.insert(nt,rt)
end
return nt
end
请批评并改进此候选解决方案。
答案 0 :(得分:3)
我在您的代码中修改了一些内容,我认为它现在按预期工作,我已添加内联注释。
function map(func, array)
local new_array = {}
for i, v in ipairs(array) do
new_array[#new_array + 1] = func(v)
end
return new_array
end
function mapn(func, ...)
-- Variadic arguments bound to an array.
local arrays = {...}
local new_array = {}
-- Simple for-loop.
local i = 1
while true do
local arg_list = map(function(arr) return arr[i] end, arrays)
if #arg_list == 0 then
break
end
new_array[i] = func(unpack(arg_list))
i = i + 1
end
return new_array
end
-- Using 'mapn' instead of 'map' (probably how you intended).
function zip(...)
return mapn(function(...) return {...} end,...)
end
-- Same as before.
function transpose(...)
return zip(unpack(...))
end
用法示例:
for _, row in pairs(transpose({{1,2},{3,4},{5}})) do
for _, col in pairs(row) do io.write(col .. ' ') end
io.write('\n')
end
-- Output: 1 3 5
-- 2 4
答案 1 :(得分:1)
由于以下行,您的示例中的{5}
被忽略:
if table.getn(arg_list) < arg_length then return new_array end
您可能想要做的只是在arg_list
为空时才退出循环。
如果行的长度单调增加,则会给出您想要的结果。
对于更一般的情况,后面的行可能比之前的行短
(例如{{1,2},{3,4,5},{6}}
),您需要跟踪行长度以允许漏洞。这可以通过向map
添加可选参数(和额外返回值)来完成,以指示评估i
的最大索引func(array[i])
:
function map(func, array, len)
local new_array = {}
len = len or #array
for i=1,len do
new_array[i] = func(array[i])
end
return new_array, len
end
function mapn(func, ...)
local new_array = {}
local i=1
local arg_length = select('#', ...)
local args = {...}
while true do
local arg_list, num_results = map(function(arr) return arr[i] end, args, arg_length)
if not next(arg_list) then return new_array end
new_array[i] = func(unpack(arg_list, 1, num_results))
i = i+1
end
end
function zip(...)
return mapn(function(...) return {...} end,...)
end
function transpose(...)
return zip(unpack(...))
end