2011-11-08 9 views
0

私はLuaの関数mapnとzipを使ってエレガントな転置関数を構築しようとしています。 (LUA帳から)次のように"Transpose/Zip"関数が正常に動作しません

mapnとジッパーは、次のとおりです。

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 

これらの作業を予想通り。

I次に、ジップを定義したように転置

:ここで({{1,2}、{3,4}、{5,6}})転置

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

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

は{{1,3,5生成します}、{2,4,6}}を期待どおりに使用します。

しかし、転置({{1,2}、{3,4}、{5}})は{{1,3,5}、{2,4}}を生成しません。 1行しか生成しません。

希望の結果を得るにはどうすればよいですか?


私はちょうど "面白い"関数を書くことにしました。 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 

この候補ソリューションを批判して改善してください。

+3

コードがいくつかのLUA 5.0アーティファクト(すなわち 'arg'と'テーブルを含みます.getn')。あなたがLuaでプログラミングを読んでいるなら、それが第2版であることを確認してください。 –

+2

その 'unpack(...)'は私に非常に疑わしいと思われます。それが何を理解していることを確認してください。 –

+0

あなたの投稿のコードはすべて正しいですか?私は 'transpose {{1,2}、{3,4}、{5,6}})'と 'Transpose({{1,2}、{3,4}、{5}})をテストしました'を返し、どちらの場合も' {{1}、{2}} 'を返しました。私はLua 5.1を使っています。 – kikito

答えて

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 
+0

@JohnSmithこれはうまくいくはずです、どうやってテストしていますか? – ponzao

+0

あなたの 'map'と' map'は 'ipairs'の仕組みのために同じことをします。 – Robin

+0

@ponzao:あなたが勝つ、私は少しミスをした。 –

1

あなたの例では{5}が原因でこのラインの無視されている:あなたが代わりにやりたいことは何

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

は、ループから抜け出すですarg_listが空の場合のみです。

これは、行が単調に長くなることを条件として、結果を与えます。より一般的な場合について

後行が以前のもの
(例えば{{1,2},{3,4,5},{6}})よりも短い場合、あなたは穴を可能にするために、行の長さを追跡する必要があります。これはfunc(array[i])を評価したiれる最大屈折率を示すためmapにオプションの引数(および余分戻り値)を加えることによって行うことができる。

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 
関連する問題