はじめに
C# Dojo シリーズでは、 C# のさまざまな機能の理解を深めることを目的に、基本的な練習問題と解説を提供していきたいと考えています。
いつまで続くかわかりませんが、ご活用いただけますと嬉しいです!
しばらくは Index
, Range
, Span<T>
まわりの話題が中心になると思います。
初回の今回は、 Index
構造体の基本を紹介します。解答は後日別の記事に投稿します。
今回のお題
与えられた配列の末尾から数えて
n
個目の要素を取り出す処理を書いてください(配列の最後の要素を「末尾から数えて 1 個目」とします)。
メソッド定義の例:
int GetFromEnd(int[] array, int indexFromLast) { /* ... */ }
入力例: array = [1, 2, 3, 4, 5, 6]
, indexFromLast = 3
出力例: 4 // 末尾から数えて 3 つめ
基礎知識
Index
構造体を使うと、配列や文字列、 Span<T>
内の「位置」を表すことができます。 Index
には、 2 種類の使い方があります。
- 先頭からの位置を表す
- 末尾からの位置を表す
配列のインデックスを復習しよう
先頭からの位置だけでなく、末尾からの位置を混乱なく扱うために、配列の「インデックス」が何を意味しているのかを復習しましょう。
Index
構造体登場以前から、C# の配列では、 a[1]
のようにして、整数を指定して特定の位置の要素にアクセスできました。
この 1
は「配列の先頭からの距離が 1
」ということを表しています。つまり、 a[1]
は先頭からの距離が 1
の地点から始まる要素、を表しているのです。
インデックスというのはあくまで「距離」を表すものであり、各要素に対して直接割り当てられている番号ではないことに注意しておきましょう。
(先頭からのインデックスを考えている限りはどちらの考え方でも問題なくインデックスを扱うことができます。このあと末尾からのインデックスを考えるときに両者の違いがはっきりするでしょう。)
Start-relative indexing: 先頭からの位置を表す
これは「ふつうの」インデックスです。最初の要素を取るには a[0]
のようにして、次の要素は a[1]
、その次は a[2]
... というふうになります。
つまり、「先頭からの距離」を指定する方法が Start-relative indexing です。
この場合、 Index
構造体を使った位置指定の方法は以下のようになります。
int a = { 1, 2, 3, 4, 5 }; Index index = 1; // 先頭からの距離が 1 の場所を表すインデックス int second = a[index]; // 先頭からの距離が 1 の要素 (= 2) を取り出す
Index
構造体を使わずに、以下のように書いても同じことです(こちらのほうが馴染み深いでしょう)。
int second = a[1];
End-relative indexing: 末尾からの位置を表す
こちらは見慣れない方も多いかもしれません。 End-relative indexing では、末尾からの距離を使って位置を表現します。
Start-relative indexing では先頭からの距離をそのまま書いていたのですが、 End-relative indexing では、 ^1
のように距離に ^
をつけて表現します。
^1
というのは、「末尾からの距離が 1
の位置」ということになります。
int a = { 1, 2, 3, 4, 5 }; Index index = ^1; // 末尾からの距離が 1 の場所を表すインデックス int second = a[index]; // 末尾からの距離が 1 の要素 (= 5) つまり、最後の要素を取り出す
Index
構造体を明示的に使わずに、以下のように書くこともできます。
int second = a[^1];
このとき注意してほしいのが、 一番最後の要素は a[^0]
ではなく、 a[^1]
になるという点です。
先頭の要素が a[0]
で、末尾の要素が a[^1]
というのは奇妙に思える方は、インデックスが「距離」を表しているということを念頭にもう一度考えてみましょう。
End-relative indexing では、「配列の末尾」からの距離を表します。ここで、 ^0
は配列の終わりを表します。
^0
は配列の終わりですから、 ^0
の部分になにか要素が格納されているということはありません。最後の要素は ^1
の地点から始まっているのです。
Index の例
- 先頭からの距離が
3
int[] a = {1, 2, 3, 4, 5}; int element = a[3]; // 4
- 末尾からの距離が
3
int[] a = {1, 2, 3, 4, 5}; int element = a[^3]; // 3