(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

(:3[kanのメモ帳]


本ブログの運営者kan.kikuchiが個人で開発したゲームです!


任意の値に最も近い値を取得するLINQの拡張メソッド【Unity】【C#】【LINQ】【拡張メソッド】


このエントリーをはてなブックマークに追加



はじめに

LINQには同じ値を取得するというメソッドはありますが、

//検索対象のList
var list = new List<int>() {
  -11, 0, 5, 8, 24, 100
};

//Listの中から0を取得(なければデフォルト値)
var targetValue = list.FirstOrDefault(value => value == 0);


一番近い値を取得するメソッドはありません。


と言う事で今回は任意の値に最も近い値を取得する

LINQの拡張メソッド を作ってみようという感じの記事です!

f:id:kan_kikuchi:20220226071913j:plain


なお、Unityでの使用を想定しているためDebugやMathfを使っています。


任意の値に最も近い値を取得するLINQの拡張メソッド

まず、最も近い値をどうすれば計算すればいいのかというと、

「目的の値に最も近い値を選ぶ」という要求は、「目的の値との差の絶対値が最小の値を選ぶ」


という感じで差の絶対値を計算してそれが最小の物を選べばいいわけです。

絶対値はMathfのAbsで、最小値はLINQのminで取得出来るので

LINQの拡張メソッドとして実装すると以下のような感じになります。

using System.Collections.Generic;
using System.Linq;
using UnityEngine;

/// <summary>
/// LINQの拡張クラス
/// </summary>
public static class LINQExtension {

  //=================================================================================
  //目的の値に最も近い値の取得
  //=================================================================================

  /// <summary>
  /// 目的の値に最も近い値を取得(int用)
  /// </summary>
  public static int Nearest(this IEnumerable<int> source, int targetValue){
    if (source.Count() == 0) {
      Debug.LogError($"値が入っていないので、最も近い値を取得出来ません");
      return targetValue;
    }
    
    //目的の値との差の絶対値が最小の値を計算
    var min = source.Min(value => Mathf.Abs(value - targetValue));
    
    //絶対値が最小の値だった物を最も近い値として返す
    return source.First(value => Mathf.Abs(value - targetValue) == min);
  }
  
  /// <summary>
  /// 目的の値に最も近い値を取得(float用)
  /// </summary>
  public static float Nearest(this IEnumerable<float> source, float targetValue){
    if (source.Count() == 0) {
      Debug.LogError($"値が入っていないので、最も近い値を取得出来ません");
      return targetValue;
    }
    
    //目的の値との差の絶対値が最小の値を計算
    var min = source.Min(value => Mathf.Abs(value - targetValue));
    
    //絶対値が最小の値だった物を最も近い値として返す
    return source.First(value => Mathf.Approximately(Mathf.Abs(value - targetValue), min));
  }
  
}


実際に使ってみると以下のような感じになります。(floatでもok)

//検索対象のList
var list = new List<int>() {
  -11, 0, 5, 8, 24, 100
};
    
//検索する値
var targetValue = 2;
    
//Listの中から2に一番近い値を取得
var nearestValue = list.Nearest(targetValue);
    
//検索結果をログで表示
Debug.Log($"{string.Join(", ", list)}の中で{targetValue}に最も近い値は{nearestValue}です");
f:id:kan_kikuchi:20220226071913j:plain