テーブルユーティリティ

以下のスクリプトを貼り付けると、table.copyとtable.stable_copyの二つのメソッドが追加される。
table.copyはtableをコピーする。コピー対象にテーブルが含まれていたら、それの中身をさらにコピーする。他の言語ではクローンとか言われるような動作をする。
table.stable_sortは、安定ソートを提供する。たぶん。使い方はtable.sortと同じだが、引数に細工をして簡単に使えるようにした。後述。

do
	-- テーブルをコピーする。
	-- テーブルが入っている場合は、そのものではなくてそのコピーを使う。
	table.copy = function(t)
		local res = {}
		for k, v in pairs(t) do
			if type(v)=="table" then v = table.copy(v) end
			res[k] = v
		end
		return res
	end

	local default_func = function(a, b) -- デフォルトの比較関数
		if a>b then return true end
		return false
	end
	
	table.stable_sort = function(t, func) -- table.sortの安定ソート版
		if #t<2 then return false end -- 項目数が1個なら、ソートは発生しない。
		-- ソートアルゴリズムを特定
		-- funcが文字列ないし数値であれば、それぞれの項目をテーブルとみなし、そのテーブルのfuncと同じキーを比較対象にする。
		if type(func)=="string" or type(func)=="number" then
			local key = func
			func = function(a, b)
				if a[key]>b[key] then return true end
				return false
			end
		end
		-- さらにそうでもなければ、デフォルトの比較関数が使われる。単純な昇順である。
		if type(func)~="function" then func = default_func end
		local temp
		for max = #t, 2, -1 do
			for cursor = 1, max-1 do
				if func(t[cursor], t[cursor+1]) then
					temp = t[cursor]
					t[cursor] = t[cursor+1]
					t[cursor+1] = temp
				end
			end
		end
		return true
	end
end

table.stable_sortの使い方

table.stable_sort(t)

このようにした場合、tの各項目は数値が期待され、昇順になる。

table.stable_sor(t, "speed")

このようにした場合、tの各項目はtableが期待され、各項目の["speed"]が比較対象になり、安定昇順になる。
RPGのキャラクターを入れて、その速度で行動順を決めるなどに使える。

local func = function(a, b)
	-- ごちゃごちゃ
end
table.stable_sort(t, func)

第二引数に関数を渡した場合、その関数が比較に使われる。
比較関数は、二つの引数を取り、boolean型を返すことが期待されている。
boolean型でtrueを返した場合、項目のスワップが発生する。
一度に複数の項目での比較などをする場合は、これを使う。
ちなみに、

local func = function(...)
	if math.random(2)==1 then return true end
	return false
end

こういう関数を渡した場合、ランダムなシャッフルになるのはみなさんよくご存知。

local func = function(a, b)
	if (a.speed + math.random(6)) > (b.speed + math.random(6)) then return true end
	return false
end

それぞれのspeed値にそった並べかえが行われるが、乱数の要素も含むなどこんな感じか。

注意点

なお、使われているアルゴリズムバブルソートなので、速度的には最悪になる。
まさに、RPGの敵味方行動順くらいにしか使い道はなさそう。