<Lua> Luaで数値を用いたfor文でループ処理を行う

Last modified: 2019-07-21

ここでは数値を用いる形のfor文によるループ処理を扱う。

解説

数値を用いたループについて

同じような形の処理を特定の回数だけ繰り返したい際にfor文という構文が役立つ。

Luaのfor文には数値を用いたものと汎用のものがあり、ここで扱うのは数値を用いたほうの形となる。

for文ではループ用の変数(ループ変数・ループカウンタ)を用意してループ内でのみ1これを参照することができ、例えば、現在何回目の繰り返しになっているかを取得するのに使える。

ループ変数の値が1ずつ増える場合の形

for [ループ変数] = [最初の値], [ループを抜ける基準の値] do
  -- [処理...]
end

値が整数で1ずつ増える形においては、コンマの右の値は最後にとる値となる。

例えば

$ lua -e "for i = 1, 10 do print(('%2d 行目'):format(i)); end"

とすると、実行結果は

 1 行目
 2 行目
 3 行目
 4 行目
 5 行目
 6 行目
 7 行目
 8 行目
 9 行目
10 行目

となる。

ループ変数の刻み幅を指定する場合の形

コンマをはさんだ2つ目の値の後ろに更にコンマを付けてその後ろに刻み幅を指定することもできる。2

for [ループ変数] = [最初の値], [ループを抜ける基準の値], [刻み幅] do
  -- [処理...]
end

これにより、ループ用の変数が1ずつ増える以外に

  • 3ずつ増える
  • 1ずつ減らす

など、任意の値で変化させられる。ループ用の変数の値の変化はコンマの右の値をまたがない(範囲内の)最後の値で止まる。

$ lua -e "for i = 10, 1, -1 do print(('末尾から %2d 行目'):format(i)); end"
末尾から 10 行目
末尾から  9 行目
末尾から  8 行目
末尾から  7 行目
末尾から  6 行目
末尾から  5 行目
末尾から  4 行目
末尾から  3 行目
末尾から  2 行目
末尾から  1 行目

小数点以下がある場合でもループができる。

$ lua -e "for i = 0, 1, 0.3 do print(('%.1f'):format(i)); end"
0.0
0.3
0.6
0.9

$ lua -e "for i = 1, 0, -0.3 do print(('%.1f'):format(i)); end"
1.0
0.7
0.4
0.1

ループから抜ける記述

for文のdoendの間のどこかで(条件しだいで)ループを抜けるようにしたい場合、抜けたいところでbreak文を記述する。

for [略] do
  -- ...
  if [条件] then
  -- ...
    break
  end
  -- ...
end
-- break文の後はここに来る

コード例

[任意]ファイル名:007_for_number.lua エンコーディング:UTF-8

#! /usr/bin/lua
-- -*- coding: utf-8 -*-

--[[--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
動作確認バージョン: 5.3, JIT2.1
--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --]]

-----
----- 数値を用いたfor文の処理
-----

-- 連番URLを生成する例
-- 「for [ループ変数] = [最初の値], [ループを抜ける基準の値] (, [刻み幅]) do [処理...] end」の形
-- 刻み幅は1の場合に省略可
-- ループ変数iは1から2,3,4,と増えて10までの値をとって「end」までの内容を処理する
for i = 1, 10 do
    print(('http://www.example.com/image/%03d.jpg'):format(i))
end

-- 表示区切り
print(('-'):rep(80))

-- for文の中にfor文を入れて九九の一覧を生成
for i = 1, 9 do
    for j = 1, 9 do
        io.stdout:write(('%d x %d = %d'):format(i, j, i * j))
        -- j(内側のループ変数)の値によって条件分岐する
        -- ここでは段ごとに1行になるような見た目の目的
        if j < 9 then
            -- jが9より小さい場合の処理
            io.stdout:write(', ')  -- 区切りの文字列を出力
        else
            -- jが9以上(ここでは9のみ該当)の場合の処理
            io.stdout:write('\n')  -- 「段」の最後で改行する
        end
    end
end

print(('-'):rep(80))

-- 刻み幅を指定する場合の例
-- 8から0.12ずつ減らしたものを表示
for i = 8.0, 7.0, -0.12 do
    print(('%.2f'):format(i))
end

print(('-'):rep(80))

-- 「end」の外側ではループ変数の値は参照できない(値「nil」が得られる)
print(('i:%s'):format(i))

print(('-'):rep(80))

-- 外側でループ変数の値が使いたい場合はループ内で別の変数に入れる
-- 文字列「abcdefg」の中で最初に「e」が見つかった位置を得る例
-- (実際にはstring.find()が便利)
do
    local result = nil
    local s = 'abcdefg'
    for i = 1, s:len() do
        -- 「s:sub(i, i)」は半角文字列sのi文字目だけを得る
        if s:sub(i, i) == 'e' then
            result = i
            -- これ以上ループをする必要がないのでbreak文でループを抜ける
            break
        end
    end
    if result then
        print(('半角文字列 "%s" の中で最初の "e" は %d 文字目です'):format(s, result))
    end
end

-- 終了

下は実行結果。

http://www.example.com/image/001.jpg
http://www.example.com/image/002.jpg
http://www.example.com/image/003.jpg
http://www.example.com/image/004.jpg
http://www.example.com/image/005.jpg
http://www.example.com/image/006.jpg
http://www.example.com/image/007.jpg
http://www.example.com/image/008.jpg
http://www.example.com/image/009.jpg
http://www.example.com/image/010.jpg
--------------------------------------------------------------------------------
1 x 1 = 1, 1 x 2 = 2, 1 x 3 = 3, 1 x 4 = 4, 1 x 5 = 5, 1 x 6 = 6, 1 x 7 = 7, 1 x 8 = 8, 1 x 9 = 9
2 x 1 = 2, 2 x 2 = 4, 2 x 3 = 6, 2 x 4 = 8, 2 x 5 = 10, 2 x 6 = 12, 2 x 7 = 14, 2 x 8 = 16, 2 x 9 = 18
3 x 1 = 3, 3 x 2 = 6, 3 x 3 = 9, 3 x 4 = 12, 3 x 5 = 15, 3 x 6 = 18, 3 x 7 = 21, 3 x 8 = 24, 3 x 9 = 27
4 x 1 = 4, 4 x 2 = 8, 4 x 3 = 12, 4 x 4 = 16, 4 x 5 = 20, 4 x 6 = 24, 4 x 7 = 28, 4 x 8 = 32, 4 x 9 = 36
5 x 1 = 5, 5 x 2 = 10, 5 x 3 = 15, 5 x 4 = 20, 5 x 5 = 25, 5 x 6 = 30, 5 x 7 = 35, 5 x 8 = 40, 5 x 9 = 45
6 x 1 = 6, 6 x 2 = 12, 6 x 3 = 18, 6 x 4 = 24, 6 x 5 = 30, 6 x 6 = 36, 6 x 7 = 42, 6 x 8 = 48, 6 x 9 = 54
7 x 1 = 7, 7 x 2 = 14, 7 x 3 = 21, 7 x 4 = 28, 7 x 5 = 35, 7 x 6 = 42, 7 x 7 = 49, 7 x 8 = 56, 7 x 9 = 63
8 x 1 = 8, 8 x 2 = 16, 8 x 3 = 24, 8 x 4 = 32, 8 x 5 = 40, 8 x 6 = 48, 8 x 7 = 56, 8 x 8 = 64, 8 x 9 = 72
9 x 1 = 9, 9 x 2 = 18, 9 x 3 = 27, 9 x 4 = 36, 9 x 5 = 45, 9 x 6 = 54, 9 x 7 = 63, 9 x 8 = 72, 9 x 9 = 81
--------------------------------------------------------------------------------
8.00
7.88
7.76
7.64
7.52
7.40
7.28
7.16
7.04
--------------------------------------------------------------------------------
i:nil
--------------------------------------------------------------------------------
半角文字列 "abcdefg" の中で最初の "e" は 5 文字目です
  • 使用したバージョン
    • Lua 5.3.3
    • LuaJIT 2.1.0 Beta 3

  1. ループ外で値が必要な場合、ループ外でも参照できる別の変数にその値を入れる [return]
  2. “省略時の刻み幅が1” とも言える [return]