Как элегантно проверить, находится ли число в пределах диапазона? - PullRequest
129 голосов
/ 06 июля 2010

Как я могу сделать это элегантно с C # и .NET 3.5 / 4?

Например, число может быть между 1 и 100.

Я знаю простого if, если его будет достаточно;но ключевое слово в этом вопросе - элегантность.Это для моего игрушечного проекта не для производства.

Этот вопрос был не о скорости, а о красоте кода.Хватит говорить об эффективности и тому подобном;помните, что вы проповедуете хору.

Ответы [ 23 ]

0 голосов
/ 22 сентября 2017

При проверке, находится ли «число» в диапазоне, вы должны четко понимать, что вы имеете в виду, и что означают два равных числа? В общем случае вы должны обернуть все числа с плавающей запятой в так называемый «эпсилон-шар», для этого нужно выбрать небольшое значение и сказать, что если два значения находятся слишком близко, это одно и то же.

    private double _epsilon = 10E-9;
    /// <summary>
    /// Checks if the distance between two doubles is within an epsilon.
    /// In general this should be used for determining equality between doubles.
    /// </summary>
    /// <param name="x0">The orgin of intrest</param>
    /// <param name="x"> The point of intrest</param>
    /// <param name="epsilon">The minimum distance between the points</param>
    /// <returns>Returns true iff x  in (x0-epsilon, x0+epsilon)</returns>
    public static bool IsInNeghborhood(double x0, double x, double epsilon) => Abs(x0 - x) < epsilon;

    public static bool AreEqual(double v0, double v1) => IsInNeghborhood(v0, v1, _epsilon);

С этими двумя помощниками на месте и предполагая, что если любое число может быть брошено как двойное без необходимой точности. Все, что вам сейчас нужно, это перечисление и другой метод

    public enum BoundType
    {
        Open,
        Closed,
        OpenClosed,
        ClosedOpen
    }

Другой метод следующий:

    public static bool InRange(double value, double upperBound, double lowerBound, BoundType bound = BoundType.Open)
    {
        bool inside = value < upperBound && value > lowerBound;
        switch (bound)
        {
            case BoundType.Open:
                return inside;
            case BoundType.Closed:
                return inside || AreEqual(value, upperBound) || AreEqual(value, lowerBound); 
            case BoundType.OpenClosed:
                return inside || AreEqual(value, upperBound);
            case BoundType.ClosedOpen:
                return inside || AreEqual(value, lowerBound);
            default:
                throw new System.NotImplementedException("You forgot to do something");
        }
    }

Теперь это может быть намного больше, чем вы хотели, но это мешает вам постоянно иметь дело с округлением и попыткой вспомнить, округлено ли значение и до какого места. Если вам нужно, вы можете легко расширить это для работы с любым эпсилоном и позволить вашему эпсилону измениться.

0 голосов
/ 13 мая 2017

Я искал элегантный способ сделать это, где границы могут быть переключены (т.е. не уверен, в каком порядке находятся значения).

Это будет работать только на более новых версиях C #, где?: Существует

bool ValueWithinBounds(float val, float bounds1, float bounds2)
{
    return bounds1 >= bounds2 ?
      val <= bounds1 && val >= bounds2 : 
      val <= bounds2 && val >= bounds1;
}

Очевидно, что вы могли бы изменить там знак = для ваших целей.Могли бы получить фантазию с типом литья тоже.Мне просто нужно возвращение с плавающей точкой в ​​пределах (или равных)

0 голосов
/ 08 ноября 2013

Я бы пошел с более простой версией:

if(Enumerable.Range(1,100).Contains(intInQuestion)) { ...DoStuff; }
...