table.sort を使用して連想インデックスを持つテーブルをソートできないのはなぜですか?
3 に答える
一般に、Lua テーブルは純粋な連想配列です。Lua コアで使用される特定のハッシュ テーブル実装の副作用として以外に、「自然な」順序はありません。Lua データ型 ( 以外nil
) の値はキーと値の両方として使用できるため、これは理にかなっています。ただし、文字列と数値のみが何らかの適切な順序付けを持ち、同様のタイプの値の間のみです。
たとえば、このテーブルのソート順は次のようになります。
unsortable = {
answer=42,
true="Beauty",
[function() return 17 end] = function() return 42 end,
[math.pi] = "pi",
[ {} ] = {},
12, 11, 10, 9, 8
}
これには、1 つの文字列キー、1 つのブール キー、1 つのファンクション キー、1 つの非整数キー、1 つのテーブル キー、および 5 つの整数キーがあります。関数は文字列の前にソートする必要がありますか? 文字列と数値をどのように比較しますか? テーブルはどこでソートする必要がありますか? また、この表に出userdata
てthread
こない値についてはどうでしょうか?
慣例により、1 で始まる連続した整数でインデックス付けされた値は、一般的にリストとして使用されます。いくつかの関数と一般的なイディオムは、この規則に従っており、table.sort
一例です。リストを操作する関数は、通常、リストの一部ではないキーに格納されている値を無視します。もう一度table.sort
例を示します。リストの一部であるキーに格納されている要素のみを並べ替えます。
もう 1 つの例は、#
オペレーターです。上記の表では、は#unsortable
5 です。数値インデックスに格納されている値は、pi が 3 から 4 の間であっても、整数ではないためカウントされないことに注意してください。さらに、他の非整数キーもカウントされません。これは、単純な for ループがリスト全体を反復できることを意味します。unsortable[5] ~= nil
unsortable[6] == nil
math.pi
for i in 1,#unsortable do
print(i,unsortable[i])
end
と書かれることが多いですが、
for i,v in ipairs(unsortable) do
print(i,v)
end
つまり、Lua テーブルは値の順序付けられていないコレクションであり、それぞれがキーによってインデックス付けされています。ただし、1 から始まる連続した整数キーには特別な規則があります。
編集:適切な部分順序付けを持つ非整数キーの特殊なケースについては、別のインデックス テーブルを含む回避策があります。文字列値をキーとするテーブルの記述内容は、このトリックの適切な例です。
まず、キーを新しいテーブルにリスト形式で収集します。つまり、キーを値として 1 から始まる連続した整数でインデックス付けされたテーブルを作成し、それを並べ替えます。次に、そのインデックスを使用して、元のテーブルを目的の順序で反復処理します。
たとえば、次の はforeachinorder()
、この手法を使用してテーブルのすべての値を反復処理し、比較関数によって決定された順序で各キーと値のペアに対して関数を呼び出します。
function foreachinorder(t, f, cmp)
-- first extract a list of the keys from t
local keys = {}
for k,_ in pairs(t) do
keys[#keys+1] = k
end
-- sort the keys according to the function cmp. If cmp
-- is omitted, table.sort() defaults to the < operator
table.sort(keys,cmp)
-- finally, loop over the keys in sorted order, and operate
-- on elements of t
for _,k in ipairs(keys) do
f(k,t[k])
end
end
インデックスを構築し、それを でソートしてから、ソートされたtable.sort()
インデックス内の各要素をループし、それぞれに対して関数を呼び出しますf
。関数f
にはキーと値が渡されます。ソート順は、 に渡されるオプションの比較関数によって決定されますtable.sort
。比較する 2 つの要素 (この場合はテーブルへのキー) で呼び出され、最初の要素が 2 番目の要素よりも小さい場合にt
返される必要があります。true
省略した場合table.sort
、組み込み<
演算子を使用します。
たとえば、次の表があるとします。
t1 = {
a = 1,
b = 2,
c = 3,
}
次にforeachinorder(t1,print)
印刷します:
1 b 2 c 3
とforeachinorder(t1,print,function(a,b) return a>b end)
印刷:
c 3 b 2 1
1 から始まる連続した整数キーを持つテーブル、つまりリストのみをソートできます。キーと値のペアの別のテーブルがある場合は、ペアのリストを作成して並べ替えることができます。
function sortpairs(t, lt)
local u = { }
for k, v in pairs(t) do table.insert(u, { key = k, value = v }) end
table.sort(u, lt)
return u
end
もちろん、これは、lt
キーと値のペアを引数として期待するカスタム順序付け ( ) を提供する場合にのみ役立ちます。
この問題は、Lua テーブルの並べ替えに関する関連する質問で詳しく説明されています。
そもそも彼らには秩序がないからです。バナナがいっぱい入ったゴミ袋を分別しようとしているようなものです。