コガネブログ

平日更新を目標に Unity や C#、Visual Studio、ReSharper などのゲーム開発アレコレを書いていきます

【C#】配列やリストから目的の値に最も近い値を取得する拡張メソッド その2

ソースコード

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

public static class IEnumerableExtensions
{
   #region Nearest

    /// <summary>
    /// 目的の値に最も近い値を返します
    /// </summary>
    public static int Nearest( 
        this IEnumerable<int> self, 
        int target
    )
    {
        var min = self.Min( c => Math.Abs( c - target ) );
        return self.First( c => Math.Abs( c - target ) == min );
    }

    /// <summary>
    /// 目的の値に最も近い値を返します
    /// </summary>
    public static int Nearest<TSource>( 
        this IEnumerable<TSource> self, 
        int target, 
        Func<TSource, int> selector
    )
    {
        var min = self.Min( c => Math.Abs( selector( c ) - target ) );
        return selector( self.First( c => Math.Abs( selector( c ) - target ) == min ) );
    }

    /// <summary>
    /// 目的の値に最も近い値を持つ要素を返します
    /// </summary>
    public static TSource FindNearest<TSource>( 
        this IEnumerable<TSource> self, 
        int target, 
        Func<TSource, int> selector
    )
    {
        var min = self.Min( c => Math.Abs( selector( c ) - target ) );
        return self.First( c => Math.Abs( selector( c ) - target ) == min );
    }

   #endregion

   #region NearestMoreThan

    /// <summary>
    /// 目的の値に最も近く、目的の値より大きい値を返します
    /// </summary>
    public static int NearestMoreThan( 
        this IEnumerable<int> self, 
        int target
    )
    {
        var list = self.Where( c => target < c ).ToArray();
        var min = list.Min( c => Math.Abs( c - target ) );
        return list.First( c => Math.Abs( c - target ) == min );
    }

    /// <summary>
    /// 目的の値に最も近く、目的の値より大きい値を返します
    /// </summary>
    public static int NearestMoreThan<TSource>( 
        this IEnumerable<TSource> self, 
        int target, 
        Func<TSource, int> selector
    )
    {
        var list = self.Where( c => target < selector( c ) ).ToArray();
        var min = list.Min( c => Math.Abs( selector( c ) - target ) );
        return selector( list.First( c => Math.Abs( selector( c ) - target ) == min ) );
    }

    /// <summary>
    /// 目的の値に最も近く、目的の値より大きい値を持つ要素を返します
    /// </summary>
    public static TSource FindNearestMoreThan<TSource>( 
        this IEnumerable<TSource> self, 
        int target, 
        Func<TSource, int> selector
    )
    {
        var list = self.Where( c => target < selector( c ) ).ToArray();
        var min = list.Min( c => Math.Abs( selector( c ) - target ) );
        return list.First( c => Math.Abs( selector( c ) - target ) == min );
    }

   #endregion

   #region NearestOrMore

    /// <summary>
    /// 目的の値に最も近く、目的の値以上の値を返します
    /// </summary>
    public static int NearestOrMore( 
        this IEnumerable<int> self, 
        int target
    )
    {
        var list = self.Where( c => target <= c ).ToArray();
        var min = list.Min( c => Math.Abs( c - target ) );
        return list.First( c => Math.Abs( c - target ) == min );
    }

    /// <summary>
    /// 目的の値に最も近く、目的の値以上の値を返します
    /// </summary>
    public static int NearestOrMore<TSource>( 
        this IEnumerable<TSource> self, 
        int target, 
        Func<TSource, int> selector
    )
    {
        var list = self.Where( c => target <= selector( c ) ).ToArray();
        var min = list.Min( c => Math.Abs( selector( c ) - target ) );
        return selector( list.First( c => Math.Abs( selector( c ) - target ) == min ) );
    }

    /// <summary>
    /// 目的の値に最も近く、目的の値以上の値を持つ要素を返します
    /// </summary>
    public static TSource FindNearestOrMore<TSource>( 
        this IEnumerable<TSource> self, 
        int target, 
        Func<TSource, int> selector
    )
    {
        var list = self.Where( c => target <= selector( c ) ).ToArray();
        var min = list.Min( c => Math.Abs( selector( c ) - target ) );
        return list.First( c => Math.Abs( selector( c ) - target ) == min );
    }

   #endregion

   #region NearestOrLess

    /// <summary>
    /// 目的の値に最も近く、目的の値以下の値を返します
    /// </summary>
    public static int NearestOrLess( 
        this IEnumerable<int> self, 
        int target
    )
    {
        var list = self.Where( c => c <= target ).ToArray();
        var min = list.Min( c => Math.Abs( c - target ) );
        return list.First( c => Math.Abs( c - target ) == min );
    }

    /// <summary>
    /// 目的の値に最も近く、目的の値以下の値を返します
    /// </summary>
    public static int NearestOrLess<TSource>( 
        this IEnumerable<TSource> self, 
        int target, 
        Func<TSource, int> selector
    )
    {
        var list = self.Where( c => selector( c ) <= target ).ToArray();
        var min = list.Min( c => Math.Abs( selector( c ) - target ) );
        return selector( list.First( c => Math.Abs( selector( c ) - target ) == min ) );
    }

    /// <summary>
    /// 目的の値に最も近く、目的の値以下の値を持つ要素を返します
    /// </summary>
    public static TSource FindNearestOrLess<TSource>( 
        this IEnumerable<TSource> self, 
        int target, 
        Func<TSource, int> selector
    )
    {
        var list = self.Where( c => selector( c ) <= target ).ToArray();
        var min = list.Min( c => Math.Abs( selector( c ) - target ) );
        return list.First( c => Math.Abs( selector( c ) - target ) == min );
    }

   #endregion

   #region NearestMoreLess

    /// <summary>
    /// 目的の値に最も近く、目的の値より小さい値を返します
    /// </summary>
    public static int NearestMoreLess( 
        this IEnumerable<int> self, 
        int target
    )
    {
        var list = self.Where( c => c < target ).ToArray();
        var min = list.Min( c => Math.Abs( c - target ) );
        return list.First( c => Math.Abs( c - target ) == min );
    }

    /// <summary>
    /// 目的の値に最も近く、目的の値より小さい値を返します
    /// </summary>
    public static int NearestMoreLess<TSource>( 
        this IEnumerable<TSource> self, 
        int target, 
        Func<TSource, int> selector
    )
    {
        var list = self.Where( c => selector( c ) < target ).ToArray();
        var min = list.Min( c => Math.Abs( selector( c ) - target ) );
        return selector( list.First( c => Math.Abs( selector( c ) - target ) == min ) );
    }

    /// <summary>
    /// 目的の値に最も近く、目的の値より小さい値を持つ要素を返します
    /// </summary>
    public static TSource FindNearestMoreLess<TSource>( 
        this IEnumerable<TSource> self, 
        int target, 
        Func<TSource, int> selector
    )
    {
        var list = self.Where( c => selector( c ) < target ).ToArray();
        var min = list.Min( c => Math.Abs( selector( c ) - target ) );
        return list.First( c => Math.Abs( selector( c ) - target ) == min );
    }

   #endregion
} 

使い方

var list = new []{ 1, 2, 4, 8, 16 };

var target = 5;
Debug.Log( list.Nearest( target ) );            // 4
Debug.Log( list.NearestMoreThan( target ) );    // 8
Debug.Log( list.NearestOrMore( target ) );      // 8
Debug.Log( list.NearestOrLess( target ) );      // 4
Debug.Log( list.NearestMoreLess( target ) );    // 4

target = 8;
Debug.Log( list.Nearest( target ) );            // 8
Debug.Log( list.NearestMoreThan( target ) );    // 16
Debug.Log( list.NearestOrMore( target ) );      // 8
Debug.Log( list.NearestOrLess( target ) );      // 8
Debug.Log( list.NearestMoreLess( target ) );    // 4

関数一覧

関数名 説明
Nearest 目的の値に最も近い値を返します
NearestMoreThan 目的の値に最も近く、目的の値より大きい値を返します
NearestOrMore 目的の値に最も近く、目的の値以上の値を返します
NearestOrLess 目的の値に最も近く、目的の値以下の値を返します
NearestMoreLess 目的の値に最も近く、目的の値より小さい値を返します

関連記事