0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

インデックスの考え方の違和感

Posted at

この記事はお気持ち表明です。

取り上げたいこと

文字列内の文字や配列の要素を指定するために使用する「インデックス」を、「文字(要素)の位置」と考えるのをやめたらどうか、という話。

単一要素を示す場合のインデックスの考え方

一般的には、以下のように「インデックス」は「文字(要素)の位置」と説明される。

文字列

String str = "にわとりがにわ";
インデックス 0 1 2 3 4 5 6
文字

配列

String[] ary = {"オレンジ", "りんご", "いちご"};
インデックス 0 1 2
要素 オレンジ りんご いちご

単一の文字(要素)を示す場合、この考え方で難なく理解できる。
まったくおかしなところはない。

範囲を説明する場合のインデックス(開始・終了位置)の考え方

これは、APIの設計指針に関する内容となる。

範囲を指定させるAPIの場合、以下の2つのパターンをよく見る

  1. 開始位置と終了位置を指定する
    • JavaのString.substringやPythonなどのsliceなど
  2. 開始位置と要素数を指定する
    • C#のString.IndexOfなど

特に前者「開始位置と終了位置を指定する」において、指定されたインデックス(が指す要素)を含むのか含まないのか、開始位置と終了位置とで異なる。
たいていは、開始位置は含み終了位置は含まない。
しかし、両方「含む」とするAPIもある(あったと思う)。
そのため、範囲を示す場合には、「インデックス=要素」という考え方だと、「含む含まない」も考えなければいけないので、若干わかりづらいと思う。

開始位置と終了位置を指定する

たとえばJavaのString#substring
開始位置は、含む。
終了位置は、含まない。
Javadocにもわざわざそう書いてある。

String str = "にわとりがにわ";
System.out.println(str.substring(1, 4)); // わとり
インデックス 0 1 2 3 4 5 6
文字

開始位置と要素数を指定する

たとえば C#のStirng#IndexOf
開始位置は、含む。
文字数は、含む含まないは関係ない。
(含む含まないで悩む必要がないので、開始位置と終了位置を指定するよりも、わかりやすいと思っている)

// String.IndexOf(string value, int startIndex, int count)
var str = "にわとりがにわ";
Console.WriteLine(str.IndexOf("にわ", 1, 3)); // -1
インデックス 0 1 2 3 4 5 6
文字
文字数 1 2 3

持論: 「インデックス=要素の隙間」

// 再掲
String str = "にわとりがにわ";
System.out.println(str.substring(1, 4)); // わとり
インデックス 0 1 2 3 4 5 6
文字

インデックスとは、要素の位置を示すのではなく、要素の隙間(開始位置)を示すと考える。
インデックスをこのように捉えていると、substring に指定する「1から4」とは、1~4の間の要素(わとり)となり、含む含まないを考慮しなくてよくなり、スッキリ。
と常々思っているのだけど、こういう説明をあまり見たことがない。

要素1つを指す場合(array[0])は、便宜上、終了位置が省略されているのであり、開始位置から1つ分の内容を指していると考えられるので矛盾はない。

余談

記事を書くに至った動機は、C#のString.LastIndexOf
これは、持論では説明できず、「要素位置=インデックス」でないと解釈できないAPI。

// String.LastIndexOf(string value, int startIndex, int count)
// value: 見つけたい語
// startIndex: 開始位置
// count: 文字数

var str = "にわとりがにわ";
Console.WriteLine(str.LastIndexOf("にわ", 5, 5)); // -1

LastIndexOfは「開始位置」の文字を含んで、先頭方向に「文字数」分を検索対象にする。
位置5の「に」を含みつつ5文字戻って位置2の「わ」まで(わとりがに)が検索範囲となり、「にわ」は存在しないことになる。

インデックス 0 1 2 3 4 5 6
文字

開始位置は「含まれる」のが一般的な考え方なので全然おかしくはないのだが、
↓のような挙動を期待していて、つまづいた。

インデックス 0 1 2 3 4 5 6
文字
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?