Tsuの雑記¯\_(ツ)_/¯

主に製作メモ・備忘録として使用。製作したアプリのリンクもあります。

【Unity】配列やリストの末尾要素を取得する【拡張メソッド】

配列の末尾要素を取得する時,array[array.Length - 1]といった回りくどい記述になると思います。

今回はこれをarray.GetLastElement()という,明瞭な表現で実行できる拡張メソッドを作りました。

本稿では,LINQ のメソッドである Last()も交えて御説明いたします。

(Unity 2018.3.0f2)


スクリプトの用意

まずは,拡張メソッド用のスクリプトを用意します。

unity3d.com

これで,System.Collections.GenericのインターフェースであるIReadOnlyList<T>GetLastElement()というメソッドを追加できました。

IReadOnlyList<T>はあらゆる型の配列やリストを包括しているため,これだけでint[]List<Vector3>などにも使用できます。

docs.microsoft.com


使用例

NewBehaviourScript.cs

using UnityEngine;
// 拡張メソッド GetLastElement を使うため
using static LastElement;

public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        // 整数配列
        var ints = new int[] { 0, 1, 2 };
        Debug.Log(ints.GetLastElement());
        // 小数配列
        var floats = new float[] { 0.1f, 1.1f, 2.1f };
        Debug.Log(floats.GetLastElement(0));
        // 文字列リスト
        var strings = new System.Collections.Generic.List<string> { "a", "b", "c" };
        Debug.Log(strings.GetLastElement(-1));
        // ベクトルリスト
        var vectors = new System.Collections.Generic.List<Vector3> { Vector3.zero, Vector3.one, Vector3.one * 2 };
        Debug.Log(vectors.GetLastElement(1));
    }
}

UnityEditor の Console 画面にログが表示されている画像
GetLastElement() それぞれの結果


解説

まずは拡張メソッドクラスであるLastElementを,using staticディレクティブで指定します。

docs.microsoft.com

これはLastElementを拡張クラスとするうえで,静的(static)にする必要があったためです。

/// <summary>
/// コンテナの末尾要素を取得する静的クラス
/// </summary>
[Obsolete("This class is obsolete. Call TsuGames.Last instead.")]
public static class LastElement

例外メッセージを定義していますが,constではなくstatic readonly修飾子を使用しています。

docs.microsoft.com

これは定数のように扱いたいものの,後に変更する可能性が有る場合の対処法です。

docs.microsoft.com

// shift の例外メッセージ
static readonly string ShiftExceptionMessage = "\"shift\" must be opposite of a count in container to 0.";

GetLastElement()メソッドにはジェネリック型パラメーターTを使用することで,複数の型に対応しています。

docs.microsoft.com

/// <summary>
/// コンテナの末尾要素を取得
/// </summary>
/// <typeparam name="T">コンテナの型</typeparam>
/// <param name="objects">コンテナ</param>
/// <param name="shift">末尾インデックスからのシフト(0以下)</param>
/// <returns>指定したインデックスの要素</returns>
[Obsolete("This method is obsolete. Call TsuGames.Last.LastElement instead.")]
public static T GetLastElement<T>(this IReadOnlyList<T> objects, int shift = 0)

整数型intの引数shiftによって「最後から-shift番目の要素」も取得できるよう,オーバーロードメソッドを定義しています。

docs.microsoft.com

/// <summary>
/// コンテナの末尾要素を取得
/// </summary>
/// <typeparam name="T">コンテナの型</typeparam>
/// <param name="objects">コンテナ</param>
/// <param name="shift">末尾インデックスからのシフト(0以下)</param>
/// <returns>指定したインデックスの要素</returns>
[Obsolete("This method is obsolete. Call TsuGames.Last.LastElement instead.")]
public static T GetLastElement<T>(this IReadOnlyList<T> objects, int shift)

shiftの値が範囲外だった時に例外メッセージを表示するため,try-catchキーワードを使います。

docs.microsoft.com

引数が範囲外だった場合の操作は,ArgumentOutOfRangeExceptionクラスで行います。

docs.microsoft.com

catchブロック内で明示的にthrowキーワードを使うと,専用の例外メッセージを表示できます。

docs.microsoft.com

// 例外が生じるおそれのある命令
try
{
    // 指定したインデックスの要素を返す
    return objects[LastIndexNumberOf(objects) + shift];
}
// 引数の例外をキャッチした場合
catch (ArgumentOutOfRangeException)
{
    // 例外を投げる
    throw new ArgumentOutOfRangeException(nameof(shift), ShiftExceptionMessage);
}

オーバーロードで共通する部分は,LastIndexNumberOf<T>()メソッドとして独立させています。

/// <summary>
/// コンテナの末尾インデックス番号
/// </summary>
/// <typeparam name="T">コンテナの型</typeparam>
/// <param name="objects">コンテナ</param>
/// <returns>末尾インデックス番号</returns>
static int LastIndexNumberOf<T>(IReadOnlyList<T> objects)

Enumerable.Last メソッドとの違い

LINQLast()メソッドでも末尾要素を取得できますが,GetLastElement<T>()メソッドは「末尾から○番目の要素」を選べます。

docs.microsoft.com

短所は,Last()メソッドにあるような「条件に該当する要素の中で最後の物」という指定が出来ない点です。

可読性の補助が目的であるため,機能は絞った物となりました。

御要望がございましたら,機能の追加や変更も検討いたします。

以上,配列やリストの末尾要素を取得する拡張メソッドの御紹介でした。

同じように文字列の末尾文字を取得する方法については,以下の記事をご覧くださいませ。

tsu-games.hatenablog.com

上記の機能と統合した拡張メソッドも,以下の記事にて紹介しております。

tsu-games.hatenablog.com