Функция «Transpose / Zip» не работает должным образом - PullRequest
0 голосов
/ 08 ноября 2011

Я пытаюсь построить элегантную функцию транспонирования, используя функции 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 ]

3 голосов
/ 08 ноября 2011

Я исправил несколько вещей в вашем коде и думаю, что теперь он работает так, как задумано, я добавил встроенные комментарии.

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 голос
/ 08 ноября 2011

{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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...