“转置/压缩”功能未按预期工作

发布于 2024-12-14 08:24:05 字数 1379 浏览 1 评论 0原文

我正在尝试使用 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 和 transpose 定义为:

function zip(...)
  return mapn(function(...) return {...} end,...)
end

function transpose(...)
  return zip(unpack(...))
end

现在 transpose({{1,2},{3,4},{5,6}}) 生成 {{1,3,5},{2,4,6}} 为预期的。

但 transpose({{1,2},{3,4},{5}}) 不会生成 {{1,3,5},{2,4}}。它只产生一行。

我怎样才能让它产生我想要的结果?


我只是决定写一个“不优雅”的函数。似乎没有顺利使用mapn和friends的方法。

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

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

I am trying to build an elegant transpose function using functions mapn and zip in Lua.

The mapn and zip are as follows (From the lua book):

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

These work as expected.

I then define zip and transpose as:

function zip(...)
  return mapn(function(...) return {...} end,...)
end

function transpose(...)
  return zip(unpack(...))
end

Now transpose({{1,2},{3,4},{5,6}}) produces {{1,3,5},{2,4,6}} as expected.

But transpose({{1,2},{3,4},{5}}) does not produce {{1,3,5},{2,4}}. It only produces one row.

How can I get it to produce the result I wish for?


I just decided to write an "inelegant" function instead. It seems there's no smooth way to use mapn and friends.

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

Please critique and improve this candidate solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

青巷忧颜 2024-12-21 08:24:05

我修复了您的代码中的一些问题,我认为它现在可以按预期工作,我已经添加了内联注释。

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

I fixed a few things in your code and I think it works now as intended, I've added comments inline.

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

Usage example:

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
李不 2024-12-21 08:24:05

由于这一行,示例中的 {5} 被忽略:

if table.getn(arg_list) < arg_length then return new_array end

您可能想要做的是仅当 arg_list 为空时才跳出循环。

如果行的长度单调增加,这将给出您想要的结果。

对于更一般的情况,后面的行可能比前面的行短
(例如 {{1,2},{3,4,5},{6}}),您需要跟踪行长度以允许存在孔。这可以通过向 map 添加可选参数(和额外的返回值)来指示 func(array[i])< 的最大索引 i 来完成。 /code> 被评估:

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

The {5} in your example is being ignored because of this line:

if table.getn(arg_list) < arg_length then return new_array end

What you may want to do instead is break out of the loop only when arg_list is empty.

This will then give the result you want provided that the rows are monotonically increasing in length.

For the more general case, when later rows may be shorter than earlier ones
(e.g. {{1,2},{3,4,5},{6}}), you will need to keep track of the row lengths to allow for holes. This can be done by adding an optional argument (and extra return value) to map to indicate the maximum index i for which func(array[i]) was evaluated:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文