“Transpose / Zip”功能无法正常工作

时间:2011-11-08 04:36:37

标签: lua

我正在尝试使用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

请批评并改进此候选解决方案。

2 个答案:

答案 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