CSのTips一覧

「上限を含むか」を決めると、ループと件数の1ずれを防ぎやすい

0から始まる配列では、要素数nに対する添字は0以上n未満。範囲は開始を含み終了を含まない半開区間でそろえると、件数を終了−開始で数えられる。

用語

半開区間
開始を含み、終了を含まない範囲。ここでは[start, end)と表す。
添字
配列などの要素の位置を指定する番号。ここでは0から数える。
境界値
範囲や条件が切り替わる値と、その近くの値。

図と例

6件を半開区間で重複なく分ける計算例

要素数6:添字は0〜5 → 前半[0, 3):0・1・2 → 後半[3, 6):3・4・5 → 終了6は含めず、合計6件

計算例:6件を3件ずつ処理するなら、内部の範囲は[0, 3)と[3, 6)。それぞれ添字0・1・2と3・4・5で、3件ずつになる。画面の1〜3件目は内部では[0, 3)であり、添字1・2・3とは違う。

実際のサービス・製品では

  • Python range

    正のstepのrangeはstop未満の値を生成する。range(3)の値は0・1・2で、3は含まない。

    資料を読む
  • JavaScript Array.slice

    非負のstartとendで指定する基本的な切り出しは、startを含みendを含まない。

    資料を読む

解説

ループ、配列の切り出し、バッチの範囲を実装するときに使う。0始まりの内部添字と、1始まりの画面上の番号を混ぜず、境界で変換する。

0始まりの配列を走査するのにi <= items.lengthと書くと、最後に要素数と同じ添字へ進んでしまう。0以上n未満という半開区間なら、通常はi < items.lengthにする。範囲を[start, end)と書くと、0 <= start <= end <= nのとき要素数はend - startで、[0, 3)の次を[3, 6)にすれば重なりも抜けもない。こうした境界値は、0件・1件・上限ちょうど・上限の前後で確かめる。APIによっては終了を含む指定もあるため、呼び出す側の仕様を確認して変換する。

トレードオフ

内部の範囲を開始と終了で持つ
得るもの:半開区間なら隣の範囲を終了から続けやすい
払うもの:終了を含む外部APIとの変換が必要な場合がある
開始位置と件数で持つ
得るもの:処理したい量がそのまま分かる
払うもの:残り件数や許可上限を確認して終了位置を求める必要がある

さらに学ぶ

チェック

添字0〜5の配列を3件ずつ分ける。半開区間[0, 3)の次の範囲は?

  1. [2, 5)
  2. [3, 6)
  3. [4, 6)
解答と解説

[3, 6)

[3, 6)なら3・4・5の3件で、前半と重ならない。[2, 5)は添字2が重複し、最後の5も抜ける。[4, 6)は添字3が抜けて2件だけになる。