Где я могу найти функцию «зажим» в .NET?
Вопрос
Я хотел бы зажать значение x
до ассортимента [a, b]
:
x = (x < a) ? a : ((x > b) ? b : x);
Это довольно простое. Но я не вижу функции «зажим» в классе библиотеки - по крайней мере не в System.Math
.
(Для не знаком, чтобы «зажим» значение - убедиться, что он лежит между несколькими максимальными и минимальными значениями. Если оно больше, чем максимальное значение, то он заменен на MAX и т. Д.)
Решение
Вы можете написать метод расширения:
public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
{
if (val.CompareTo(min) < 0) return min;
else if(val.CompareTo(max) > 0) return max;
else return val;
}
Редактировать: Методы расширения Перейдите в статические классы - поскольку это довольно низкоуровневая функция, она, вероятно, должна идти в определенном пространстве проверки в вашем проекте. Затем вы можете использовать метод в любом файле кода, который содержит Директива с использованием для пространства имен, например,
using Core.ExtensionMethods
int i = 4.Clamp(1, 3);
.NET CORE 2.0
Начиная с .NET CORE 2.0 System.Math
Теперь есть А. Clamp
Метод, который можно использовать вместо этого:
using System;
int i = Math.Clamp(4, 1, 3);
Другие советы
Пытаться:
public static int Clamp(int value, int min, int max)
{
return (value < min) ? min : (value > max) ? max : value;
}
Просто использовать Math.Min
а также Math.Max
:
x = Math.Min(Math.Max(x, a), b);
Нет ни одного, но не слишком сложно сделать один. Я нашел один здесь: зажим
Это:
public static T Clamp<T>(T value, T max, T min)
where T : System.IComparable<T> {
T result = value;
if (value.CompareTo(max) > 0)
result = max;
if (value.CompareTo(min) < 0)
result = min;
return result;
}
И его можно использовать как:
int i = Clamp(12, 10, 0); -> i == 10
double d = Clamp(4.5, 10.0, 0.0); -> d == 4.5
Там нет ни одного в системе. Маршнее пространство имен
http://msdn.microsoft.com/en-us/library/system.math_members.aspx.
Есть класс Mathhelper, где он доступен для HNA Game Studio, если это происходит то, что вы делаете:
http://msdn.microsoft.com/en-us/library/bb197892(v=xnagamestudio.31).aspx.
Просто поделиться Решение Ли С вопросами комментариев и проблемами рассматриваются, где это возможно:
public static T Clamped<T>(this T value, T min, T max) where T : IComparable<T> {
if (value == null) throw new ArgumentNullException(nameof(value), "is null.");
if (min == null) throw new ArgumentNullException(nameof(min), "is null.");
if (max == null) throw new ArgumentNullException(nameof(max), "is null.");
//If min <= max, clamp
if (min.CompareTo(max) <= 0) return value.CompareTo(min) < 0 ? min : value.CompareTo(max) > 0 ? max : value;
//If min > max, clamp on swapped min and max
return value.CompareTo(max) < 0 ? max : value.CompareTo(min) > 0 ? min : value;
}
Различия:
- Имя метода использует соответствующее значение Verb (
ed
) до (далее) указывают на то, что значение не зажимается на месте, и что, вместо этого возвращается новое значение (см. @ Комментарий jimbalter). - Уместно
null check
На всех входах (см. @ Комментарий @ Jeppestignielsen). - Свопы
min
а такжеmax
еслиmin > max
(Видеть @ Комментарий @ Jeppestignielsen).
Ограничения: нет односторонних зажимов. Если max
является NaN
, всегда возвращается NaN
(Видеть Комментарий Германа).
Используя предыдущие ответы, я конденсировал его к следующему коду для моих потребностей. Это также позволит вам зажать номер только на его мин или макс.
public static class IComparableExtensions
{
public static T Clamped<T>(this T value, T min, T max)
where T : IComparable<T>
{
return value.CompareTo(min) < 0 ? min : value.ClampedMaximum(max);
}
public static T ClampedMinimum<T>(this T value, T min)
where T : IComparable<T>
{
return value.CompareTo(min) < 0 ? min : value;
}
public static T ClampedMaximum<T>(this T value, T max)
where T : IComparable<T>
{
return value.CompareTo(max) > 0 ? max : value;
}
}
Код ниже поддерживает указание границ в любом порядке (т.е. bound1 <= bound2
, или bound2 <= bound1
). Я нашел это полезное для зажимных значений, рассчитанных из линейных уравнений (y=mx+b
) где уклон линии может быть увеличен или уменьшаться.
Я знаю: код состоит из пять супер-уродливых операторов экспрессии. Отказ Дело в том, оно работает, и тесты ниже доказывают это. Не стесняйтесь добавлять строгие ненужные скобки, если вы так желаете.
Вы можете легко создавать другие перегрузки для других числовых типов и в основном копировать / вставлять тесты.
Предупреждение: сравнение чисел плавающих точек не просто. Этот код не реализует double
Сравнение надежно. Используйте библиотеку сравнения с плавающей точкой для замены использования операторов сравнения.
public static class MathExtensions
{
public static double Clamp(this double value, double bound1, double bound2)
{
return bound1 <= bound2 ? value <= bound1 ? bound1 : value >= bound2 ? bound2 : value : value <= bound2 ? bound2 : value >= bound1 ? bound1 : value;
}
}
Тесты XUNIT / Fluentassertions:
public class MathExtensionsTests
{
[Theory]
[InlineData(0, 0, 0, 0)]
[InlineData(0, 0, 2, 0)]
[InlineData(-1, 0, 2, 0)]
[InlineData(1, 0, 2, 1)]
[InlineData(2, 0, 2, 2)]
[InlineData(3, 0, 2, 2)]
[InlineData(0, 2, 0, 0)]
[InlineData(-1, 2, 0, 0)]
[InlineData(1, 2, 0, 1)]
[InlineData(2, 2, 0, 2)]
[InlineData(3, 2, 0, 2)]
public void MustClamp(double value, double bound1, double bound2, double expectedValue)
{
value.Clamp(bound1, bound2).Should().Be(expectedValue);
}
}