4

私はLua5.2を使用していますが、この質問のために、テーブルが配列としてのみ使用されていると仮定します。

配列の末尾(配列から最初の要素を引いたもの)を返す関数は次のとおりです。

function tail(t)

   if # t <= 1 then
      return nil
   end

   local newtable = {}
   for i, v in ipairs(t) do
      if i > 1 then
          table.insert(newtable, v)
      end
   end

   return newtable
end 

例えば:

prompt> table.concat(tail({10、23、8})、 "、")

23、8

ただし、これはテーブルの新しいコピーを返すことによって実現されます。新しいテーブルの作成を回避する方法はありますか?

次の要素()へのポインタを返すCに相当するものを探していますt++。出来ますか?

4

5 に答える 5

9

すでに説明したように、これは通常不可能です。

ただし、メタテーブルを使用すると、元のテーブルを参照することで、すべてのデータをコピーせずに必要なことを実行する関数を実装できます。以下は、Lua 5.2のほとんどの操作で機能しますが、たとえば、次の場合は機能しません。tailtable.concat

function tail(t)
  return setmetatable({}, {
    __index = function(_, k) return t[k+1] end,
    __newindex = function(_, k, v) t[k+1] = v end,
    __len = function(_) return #t-1 end,
    __ipairs = function(_) return 
      function(_, i)
        if i+1==#t then return nil end
        return i+1, t[i+2] end, 
      t, 0 end,
    __pairs = function(t) return ipairs(t) end,
  })
end
于 2012-09-11T15:53:51.183 に答える
5

これは、tail()を実装するために私が知っている最も良い方法です。新しいテーブルが1つ作成されますが、それは避けられないと思います。

function tail(list)
    return { select(2, unpack(list)) }
end
于 2013-02-11T11:09:43.373 に答える
3

ニコルは、配列のスライスを参照できないということは正しいですが、やりたいことを行うためのより簡単で短い方法があります。

function tail(t)
  local function helper(head, ...) return #{...} > 0 and {...} or nil end
  return helper((table.unpack or unpack)(t))
end

print(table.concat(tail({10, 23, 8}), ", "))その後、を印刷します23,8

table.unpack or unpack( Lua 5.2でも動作するように追加されました)

于 2012-09-11T15:50:48.267 に答える
2

次の要素(t ++)へのポインターを返すCに相当するものを探しています。出来ますか?

いいえ。これが必要になる可能性がある唯一の理由はパフォーマンスです。このような機能は、低水準プログラミング言語でのみ見られます。Luaはスクリプト言語です。パフォーマンスは、これが実装されるほどの優先順位ではありません。

あなたがしているように別のテーブルを作成するかtable.remove、元のテーブルを変更するために使用します。あなたに最適な方。覚えておいてください:テーブルやユーザーデータのような大きくて重要なオブジェクトはすべて、値ではなく参照によってLuaに保存されます。

于 2012-09-11T15:16:51.863 に答える
1

メタテーブルを使用してシーケンスのビューを表示するというprapinの提案は、おおよそ私が行う方法です。役立つ可能性のある抽象化は、セグメントのメタテーブルを定義することです。これは、テーブルとオフセットインデックスのペアを返す0-ary関数にすることができます。ここでは、タプルを表すために関数のみを使用しています。次に、この関数をテーブルのように動作させるメタテーブルを定義できます。

do
  local tail_mt = {
    __index = function(f, k) local t, i=f(); return t[k+i] end,
    __newindex = function(f, k, v) local t,i=f(); t[k+1] = v end,
    __len = function(f) local t,i=f(); return #t-i end,
    __ipairs = function(f) 
      local t,i = f () 
      return
        function (_, j)
          if i+j>=#t then 
            return nil
          else
            return j+1, t[i+j+1] 
          end
        end, nil, 0 
      end,
  }
  tail_mt.__pairs = tail_mt.__ipairs -- prapin collapsed this functionality, so I do too

  function tail (t)
    if type(t) == "table" then
      return setmetatable ( function () return t, 1 end, tail_mt )
    elseif type(t) == "function" then
      local t1, i = t ()
      return setmetatable ( function () return t1, i+1 end, tail_mt )
    end
  end
end

__indexおよび__newindexメタメソッドを使用すると、f [2] = f[1]+1などのコードを記述できます。

この(テストされていない)コードは、1回限りのメタテーブルを無限に作成するわけではありませんが、サンク(0-ary関数)を呼び出してコンテンツを取得するため、おそらくprapinよりも効率が低くなります。ただし、シーケンスに関するより一般的なビューを使用するなどして機能を拡張することに興味がある場合は、これはもう少し柔軟だと思います。

于 2012-09-12T12:21:03.527 に答える