FC2ブログ
ヽ|∵|ゝ(Fantom) の 開発blog? ホーム » C# »【C#】配列 や List の TryGetValue

【C#】配列 や List の TryGetValue  


 今回はとても簡単なもので、意外と便利なもの。

 配列や List を扱う上で注意すべき点は、インデクス範囲外(Index was out of range) と null かどうかだが、毎回 null チェックや範囲外チェックをやるのは少し面倒である。

 Dictionary ではキーを用いて値の取得を試みる TryGetValue があるが、これと同じ様なものがあったら便利なのにな~、と思ったので作ってみた。



●配列, List の TryGetValue
using System;
using System.Collections.Generic;

public static class Extensions //名前は任意
{
/// <summary>
/// 配列 の TryGetValue
/// ・配列自体が null or インデクスが範囲外のとき false
/// 2021/05/17 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-397.html
/// </summary>
/// <typeparam name="T">要素の型</typeparam>
/// <param name="array">対象の配列</param>
/// <param name="idx">取得するインデクス</param>
/// <param name="value">取得成功したときの値</param>
/// <returns>true = 取得成功</returns>
public static bool TryGetValue<T>(this T[] array, int idx, out T value)
{
value = default(T);
if (array == null || idx < 0 || array.Length <= idx)
return false;

value = array[idx];
return true;
}

/// <summary>
/// List の TryGetValue
/// ・List 自体が null or インデクスが範囲外のとき false
/// 2021/05/17 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-397.html
/// </summary>
/// <typeparam name="T">要素の型</typeparam>
/// <param name="list">対象の List</param>
/// <param name="idx">取得するインデクス</param>
/// <param name="value">取得成功したときの値</param>
/// <returns>true = 取得成功</returns>
public static bool TryGetValue<T>(this List<T> list, int idx, out T value)
{
value = default(T);
if (list == null || idx < 0 || list.Count <= idx)
return false;

value = list[idx];
return true;
}
}

●メインコード例
using System;
using System.Collections.Generic;
using System.Linq;

int max = 50;
var array = Enumerable.Range(0, max).ToArray(); //0~49 まで
var list = Enumerable.Range(0, max).ToList(); //0~49 まで

int idxA = 25;
if (array.TryGetValue(idxA, out var resultA))
{
Console.WriteLine($"result value (Array) = {resultA}");
}
else
{
Console.WriteLine($"idx = {idxA} : Index was out of range or null (Array)");
}

int idxL = 50;
if (list.TryGetValue(idxL, out var resultL))
{
Console.WriteLine($"result value (List) = {resultL}");
}
else
{
Console.WriteLine($"idx = {idxL} : Index was out of range or null (List)");
}

//var res = list[100]; //Index was out of range

result value (Array) = 25
idx = 50 : Index was out of range or null (List)

 本当になんてことないものなんだけどね。できれば標準関数に欲しいくらい(笑)。

 例えば範囲外のインデクスのとき、予め Fallback 的な値を決めておく等、とても簡潔に書ける。

●例:範囲内なら配列の値を返し、範囲外なら 0 を返す
int[] arr = {0,1,2,3,4};
int GetOrFallback(int idx) => arr.TryGetValue(idx, out var res) ? res : 0;




 ところで少し話はずれるが、Dictionary で値の取得を試みるとき、どうやっているだろうか?

 例えば以下のような感じに書けると思うが、① と ② では実行速度が結構違う。

ContainsKey を用いてから取得
if (dic.ContainsKey(key))  //dic は Dictionary とする
{
var res = dic[key];
//ここで res を使った処理
}

TryGetValue で取得
if (dic.TryGetValue(key, out var res))  //dic は Dictionary とする
{
//ここで res を使った処理
}

 ① と ② は同じ結果にはなるが、実は実行速度は ① の方が約2倍かかる(遅い)。

 理由は簡単で、① は ContainsKey で1度 get, インデクサ(dic[key]) でもう1度 get の計2回 get (取得)するからである。TryGetValue は1回で済むので、その分速い。

 ほんのちょっとしたことでも、実行速度を改善できたりするので、特に高速なメインループ処理を実現したい時などに思い出してみると良い(Unity みたいな、毎フレーム回す処理には、徹底すれば意外と効果がある=アルゴリズム変更しない限りでは「手数を減らす」のが直接速度改善に繋がる)。





(関連記事)
【Unity】【C#】配列・リストのシャッフル
【C#】2次元配列(ジャグ配列・多次元配列)のソート
【C#】多次元配列とジャグ配列(2次元配列)のサイズ(長さ)、相互変換など
【C#】配列やListなどの中身(要素)を見る拡張メソッド Dump


関連記事
スポンサーサイト



category: C#

thread: プログラミング

janre: コンピュータ

tag: C#ライブラリ  C#リファレンス  配列操作 
tb: 0   cm: --


トラックバック

トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/397-58fcca78
この記事にトラックバックする(FC2ブログユーザー)

プロフィール

Social

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR

▲ Pagetop