a = {foo=10, bar=20, baz=30}
for k, v in pairs(a) do
print(k); print(v)
end
1. Luaのテーブルをpairsで繰り返すときに出力される順番が変わるのは仕様であり、仕様通りの挙動です。
解説:pairsの順番が変わる理由
- Luaのテーブルは「連想配列」として使えますが、キーと値の組み合わせの順序は保証されていません
-
pairs関数は「テーブルの全てのキーと値の組み合わせを順不同で列挙する」関数です - つまり、
pairsは「順序を気にせず、すべての要素を列挙すること」を目的としていて、 - 「順番は保証しない」ことが仕様として明確に定められています
仕様上の注意点(高校生向けに重要)
- 「順番が変わるから、同じ順に処理したい」と思っても、
pairsではできません - 順序を指定したい場合は、「数値の連続したキー(配列部分)」を使い、
ipairsを使う方法があります - ただし、
ipairsはキーが1から始まる連続した整数のテーブルでのみ順序を保証します - キーが文字列(
foo,barなど)の場合は順序は未定義です
例
local a = {foo=10, bar=20, baz=30}
for k, v in pairs(a) do
print(k, v)
end
これを複数回実行すると、例えば
foo 10
bar 20
baz 30
の順番だったり、
baz 30
foo 10
bar 20
の順番だったりします。
まとめ(重要)
-
pairsの順番は未定義・非保証なので、変わっても正常な動作です - 順序を期待したコードは間違いです
- 順序を制御したい場合は、キーが連番の配列を使い
ipairsを使いましょう
反例(やってはいけない例)
local a = {foo=10, bar=20, baz=30}
for i = 1, 3 do
print(a[i]) -- ❌ a[1], a[2], a[3] はnilなので意味なし
end
- 理由:キーが文字列なので数値キーは存在しない
- 結果:3回とも
nilが出る - 「配列のように順序通りにアクセスできる」と思ってはいけません
- 実行禁止
まとめコメント
-- Luaのpairsは順序を保証しません(仕様)
-- 順序が必要なら連番の配列とipairsを使うこと
2. Luaのテーブルで「順番通りに出力したい」場合は、キーが連続した整数の配列を使い、ipairsで繰り返す方法が正しいです。
ポイント
- 元のテーブルはキーが文字列(
foo,bar,baz)なので順序は保証されません - 順序を保証したい場合は、「順序を保持したキーのリスト(配列)」を用意する方法が一般的です
- つまり、順序付けたいキーを配列として別に持ち、順にアクセスします
変更例
元のテーブルと順序を保持する配列を作る例です。
local a = {foo=10, bar=20, baz=30}
local keys = {"foo", "bar", "baz"} -- 順序を明示的に保持
for i, key in ipairs(keys) do
print(key, a[key])
end
実行結果(順序保証)
foo 10
bar 20
baz 30
解説
-
keysは配列(1,2,3…の連続整数キー)なので、ipairsで順序通りにアクセス可能です -
a[key]で元のテーブルの値を取得しています - これにより、キーの順序を明示的に管理できます
まとめ
| 方法 | 順序保証 | 対象 |
|---|---|---|
pairs(a) |
なし(仕様) | キーが何でもよい |
ipairs(a) |
あり | 連続した整数キー(配列) |
ipairs(keys) + a[key]
|
あり(明示的管理) | 任意のキーを順序付きで扱う |
反例(間違った例)
local a = {foo=10, bar=20, baz=30}
for i = 1, 3 do
print(a[i]) -- ❌ nil nil nil(キーが整数ではないため)
end
- 理由:
a[1],a[2],a[3]は存在しません。 - 実行禁止です。
もし、テーブルの要素を順序付きで扱いたい場合は、キーを整数にするか、今回のようにキーのリストを別に管理するのがLuaでの安全な方法です。
3.連想配列から、上記のlocal keys = {"foo", "bar", "baz"} を作成するプログラムは作れますか。
連想配列(Luaのテーブル)からキーだけを取り出して配列(連番テーブル)を作るプログラムは作れます。
ただし、Luaのテーブルはキーの順序を持たないため、pairsで取得したキーの順序は不定です。
そのため、作成した配列keysの並び順は元の連想配列の「元々の順番」ではなく、任意の順序になります。
連想配列からキーだけを配列にするサンプルコード
local a = {foo=10, bar=20, baz=30}
local keys = {}
for k, _ in pairs(a) do
table.insert(keys, k)
end
-- keys は {"foo", "bar", "baz"} のような順序だが保証されない
-- 出力確認
for i, key in ipairs(keys) do
print(i, key)
end
実行例(順序は変わる可能性あり)
1 bar
2 foo
3 baz
順序を固定したい場合
- Luaの仕様上、元の連想配列の「作成順」や「書き込み順」のキーの順序を自動的に取得することはできません。
- もし特定の順序が必要なら、あらかじめ順序を示すキーの配列を自分で用意する必要があります。
まとめ
| 項目 | ポイント |
|---|---|
| 連想配列のキーを配列化 | 可能。ただし順序は保証されない(仕様) |
| 元の順序をプログラムで再現する | Lua標準仕様ではできない |
| 順序を管理したい場合 | 別途、順序を示す配列を用意する必要がある |
反例:順序を期待して自動生成配列を使う
local a = {foo=10, bar=20, baz=30}
local keys = {}
for k, _ in pairs(a) do
table.insert(keys, k)
end
for i, key in ipairs(keys) do
print(key, a[key]) -- ❌ 順序は保証されないため、元の順序と違う可能性あり
end
- 実行禁止(順序が重要な場合)
4.ipairsを使えば、連想配列でも順番に取り出すことはできますか。
いいえ、ipairsは連想配列(キーが文字列の場合)では順番に取り出せません。
理由
-
ipairsは「1から始まる連続した整数キーを持つ配列部分」にのみ使えます。 - キーが文字列(例:
foo,bar,baz)の連想配列には使えず、 -
ipairsでアクセスすると、nilになるか途中で繰り返しが止まります。
例で解説
local a = {foo=10, bar=20, baz=30}
for i, v in ipairs(a) do
print(i, v) -- ここは実行されません(a[1]がnilのため)
end
実行結果
何も出力されません。
ipairsは1から連続した整数キーを探しますが、a[1]がnilなので繰り返しは即終了します。
連想配列でipairsを使うと何が起きるか
- Luaはテーブルの配列部分(整数キーの連続)を
ipairsで順に返します。 - 文字列キーは配列部分ではないため無視されます。
連続整数キーの配列でのipairs例(正しい使い方)
local arr = {10, 20, 30} -- 連続した整数キー1,2,3を持つ配列
for i, v in ipairs(arr) do
print(i, v)
end
実行結果
1 10
2 20
3 30
まとめ
| 用途 | 使う関数 | キーの種類 | 順序保証 |
|---|---|---|---|
| 連想配列のすべて要素列挙 | pairs |
文字列など任意 | なし(順不同) |
| 配列の順序付き要素列挙 | ipairs |
1から連続した整数キー | あり(連番順) |