1
  -- original table
  t = {
    Steve = 20,
    Mary = 32,
    Tim = 15
  }

  --second table to help sort t{}    
  a = {}
  for n in pairs(t) do
    a[#a + 1] = n -- I do not completely understand this line.  
                  -- I know [#a + 1] is the iterator, but 
                  -- not a[#a + 1] and why equal that to "n"?
  end
  table.sort(a)
  for _, n in ipairs(a) do -- I do not understand the point of the underscore 
    print (n)
  end

  -- another way to perform the table.sort function        
  function pairsByKeys (t,f)
    local b = {}
    for x in pairs (t) do 
      b[#b + 1] = x
    end
    table.sort(b, f)
    local i = 0
    return function ()
      i = i + 1
      return b[i], t[b[i]]  -- I do not understand this line either?
    end
  end

特定のコードに続くコメントに、私が持っているいくつかの質問を入れました。2 つの別々のテーブルが必要な理由を (ほとんどの場合) 理解しています。1 つは情報を持ち、もう 1 つは を介し​​てその情報をソートしますipairs。と の違いを知っていpairsますipairs。しかし、私ははっきりと理解していませんa[#a + 1] = n。また、コードがわかりませんfor _, n in ipairs(a)...、なぜアンダースコア?最後に、私はラインを明確に理解していませんreturn b[i], t[b[i]]か?

table.sortをもう少しよく理解するのを手伝ってくれませんか?これらは PiL からの直接的な例です。助けてくれてありがとう!

4

3 に答える 3

6

まず最初に、Lua テーブルが実際に何であるかを理解する必要があります。表面的には、それらは連想配列またはマップ(2 つの広く知られた CS 用語) として表示され、多くの場合、ハッシュ テーブルとして実装されます。これらは、いわゆるキー(一意) とを関連付けるため、このように呼ばれます。これらは、キーによってインデックス付けされたキーと値のペアのコレクションとして表示できます。つまり、(一意の) キーを使用して対応する値を非常に迅速に見つけることができるように実装されています。

Lua テーブルの 2 つの主な特徴は、非常に強力で柔軟なデータ構造にもなっています (ただし、最初は完全に理解するのは少し難しいですが)、次のとおりです。

  1. Lua テーブルでは、あらゆる種類の値 ( を除くnil) をキーとして使用できます。ほとんどの言語では、キーは文字列に制限されているか、事前に宣言する必要がある特定の型に制限されています。Lua では、テーブルはいつでもあらゆる種類の値をキーとして保持できます。したがって、次のように定義されたテーブルは、Lua では完全に合法です。

    f = function(x) return x*x end
    t = { 1, 2, 3 }    
    tbl = {
        [t] = true,   -- `t` is the key (and a table), `true` is the value
        [f] = 12,     -- `f` is the key (and a function), `12` is the value
        [true] = f,   -- `true` is the key (boolean), `f` now is used as value
        [12] = f,     -- `12` is the key (number), `f` again as the value
        ["yup"] = t,  -- `"yup"` is the key (string), `t` now is used as value
    }
    
  2. 正の整数キーは、配列をシミュレートするために使用されるため、特別なステータスを持っています。Lua にはarrayという適切な概念がありません。Lua では、配列のようなテーブルを使用します(新しい Lua 5.2 用語を使用すると、シーケンスとも呼ばれます)。多くの場合、Lua のコンテキストで配列という用語が表示されますが、実際にはライターは配列のようなテーブルを意味します。あいまいさが生じないように、簡単にするために以下でも同じことを行います。Luaの配列とは何ですか? 正の整数キーが整数で始まり、整数1で終わるテーブルですn、つまり、その正の整数キーは数値 1、2、...、n のみです (これを別の言い方をすると、正の整数キーが集合 {1, 2,...,n} を形成すると言うことです)。その数値はシーケンス (配列) の長さnと呼ばれ、配列に適用されたときに演算子によって返される数値です。テーブルにこのプロパティがある場合、それはシーケンスと呼ばれます。つまり、配列として参照できます。次の場合、そのプロパティを持つテーブルは依然として配列であることに注意してください。#

    • 追加の非数値キー (文字列またはテーブル キーなど) があります。
    • 整数以外の追加の数値キーがあります (例: 1.23)。
    • 正ではない追加の整数キー (0または など-12) があります。

「汎用テーブル」と配列の違いは、用語の便宜上のものだけではありません。内部的には、Lua 実装は、テーブルが実際に配列であるかどうかを認識し、配列のようなテーブルを配列として使用するときに Lua テーブルが高いパフォーマンスを発揮できるようにするいくつかの最適化を実行します (たとえば、C で意味されているように)。実際、Lua 標準tableライブラリは、その関数 ( など) に渡されるテーブルtable.sortが実際には配列であり、正の整数インデックスを持つエントリでのみ動作すると想定しています。


これらすべてを念頭に置いて、投稿されたコードの難しい点を分析できます。

a = {}
for n in pairs(t) do
  a[#a + 1] = n 
end

これは一般的な for ループの例です。pairs(とりわけ)テーブル反復子関数を返します(したがってpairs反復子生成関数または反復子ジェネレータipairsと呼ばれることがあります)。この反復子関数は、機械によって繰り返し呼び出され、 のすべてのキー (および対応する値) を反復処理します。(つまり)には変数が 1 つしか表示されないため、反復中にのキーのみが取得されます。fortfornt

a[#a + 1] = n 

に格納されているキーnを tableに追加する簡単な方法にすぎません。これは配列であることがわかります。これは、a1 から始まる連続した正の整数キーのみを持つように反復中に段階的に構築されるためです。#aの現在の長さa(最初は0aあり、エントリがないため) は、 のシーケンス プロパティを中断することなくa[#a+1]、整数キーを使用して新しいエントリを作成します。#a + 1a

要約すると、そのforループは単にt配列a内のすべてのキーを収集して、それらを使用して並べ替えてから出力しtable.sortます。

table.sort(a)
for _, n in ipairs(a) do 
    print (n)
end

前のものは、ジェネリック for の別の例です。この場合、によって返されるイテレータ関数はipairs、(正の整数) キーとa反復中の値の両方を (この順序で) 返します。値を出力することのみに関心があるため (は配列であるため、キーは12、... などになります)、ダミー変数として を使用して (私たちには関係のない) キーを取得します。別の名前を使用することもできましたが、Lua では、このタスクに (完全に合法で通常の) 名前を使用するのが慣用的です。a__


の定義pairsByKeysは、分析するのが少し難しいです。pairsByKeysその目的は、反復が特定のキー順序に従って行われることを保証するテーブルを反復できる反復子関数を返す反復子ジェネレータ ( ) を持つことです(Luapairsは特定の反復順序を保証しません)。次のように使用することを意図しています。

for k, v in pairsByKeys( t ) do
    print( k, v )
end

定義を分析してみましょう。すでに分析したコードのロジック (および拡張機能) が 1 つの関数にパックされていることがわかります。

function pairsByKeys(t,f)
    local b = {}
    for x in pairs(t) do
      b[#b + 1] = x
    end
    table.sort(b, f)
    local i = 0
    return function()
      i = i + 1
      return b[i], t[b[i]] 
    end
end

最初に注意すべきことは、関数 (イテレータ) を返すことです。これは、実際には 3 つの上位値 ( 、および)pairsByKeysを持つ無名クロージャです。これは、返された関数が機械によって実行されるときに、これらの 3 つの変数を参照できることを意味します(このクロージャはステートフルイテレータの例です)。itbfor

反復子を返す前に、pairsByKeys反復されるテーブルを「前処理」して、t上で既に見たようにキーを抽出して並べ替えます。したがってb、 のすべてのキーが配置tされる順序で保持table.sort(b,f)されます。この への呼び出しには、を呼び出すときに指定できるコンパレータ関数であるtable.sort追加の引数があることに注意してください。これにより、さまざまな基準に従ってキーを並べ替えることができます (これが、私が説明した「強化」です)。fpairsByKeys

変数は、反復されたばかりiのキーのインデックスを保持します。bこの段階では反復が行われていないため (反復子はまだ作成されていません)。

ここで、イテレータ関数に注目しましょう:

function()
  i = i + 1
  return b[i], t[b[i]] 
end

これが機械によって呼び出されるたびforに、 がインクリメントされ、次に反復されるキーであるiがフェッチされ (順序に関する情報を保持しているため、 から取得されます)、再度使用して対応する値がフェッチされます。この情報を保持する元のテーブルから。キーと値の両方が返されます。これらの 2 つの値は、(各反復で) ループ変数と上記の例に割り当てられた値であり、出力されます。b[i]bbb[i]t[b[i]]tkv

于 2013-09-28T11:35:34.283 に答える