Question

Je voudrais serrer une x de valeur à une plage [a, b]:

x = (x < a) ? a : ((x > b) ? b : x);

Ceci est assez basique. Mais je ne vois pas une fonction « pince » dans la bibliothèque de classes -. Au moins pas dans System.Math

(Pour le pas au courant de « pince » une valeur est de vous assurer qu'il se trouve entre certaines valeurs maximales et minimales. Si elle est supérieure à la valeur maximale, il est remplacé par le maximum, etc.)

Était-ce utile?

La solution

Vous pouvez écrire une méthode d'extension:

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;
}

EDIT: Méthodes d'extension vont dans les classes statiques - car cela est tout à fait fonction de bas niveau, il devrait aller probablement dans un espace de noms de base dans votre projet. Vous pouvez ensuite utiliser la méthode dans un fichier de code qui contient une directive à l'aide de l'espace de noms par exemple.

using Core.ExtensionMethods

int i = 4.Clamp(1, 3);

.NET Core 2.0

A partir de System.Math .NET Core 2.0 a maintenant un Clamp méthode qui peut être utilisé à la place:

using System;

int i = Math.Clamp(4, 1, 3);

Autres conseils

Essayez:

public static int Clamp(int value, int min, int max)  
{  
    return (value < min) ? min : (value > max) ? max : value;  
}

Il suffit d'utiliser Math.Min et Math.Max:

x = Math.Min(Math.Max(x, a), b);

Il n'y a pas un, mais il est pas trop difficile de faire un. J'ai trouvé un ici:

Il est:

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;
    }

Et il peut être utilisé comme:

int i = Clamp(12, 10, 0); -> i == 10
double d = Clamp(4.5, 10.0, 0.0); -> d == 4.5

Il n'y a pas un dans l'espace de noms System.Math

http://msdn.microsoft.com/en-us/ bibliothèque / system.math_members.aspx

Il y a une classe MathHelper où il est disponible pour le studio de jeu XNA si cela arrive à être ce que vous faites:

http://msdn.microsoft.com /en-us/library/bb197892(v=XNAGameStudio.31).aspx

solution de Lee avec les questions et les préoccupations des commentaires adressés, si possible:

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;
}

Différences:

  • Nom de la méthode utilise le verbe approprié (ed) à (plus) indiquent que la valeur est fixée en place, et que, au contraire, une nouvelle valeur est retournée (Voir @ commentaire de JimBalter).
  • Est-null check appropriée sur toutes les entrées (voir @ commentaire de JeppeStigNielsen).
  • Swaps min et max si min > max (Voir @ commentaire de JeppeStigNielsen).

Limitations: Pas de pinces à sens unique. Si max est NaN, retourne toujours NaN (Voir commentaire de Herman de).

En utilisant les réponses précédentes, je condensé vers le bas au-dessous du code pour mes besoins. Cela vous permettra également de serrer un seul numéro par son min ou max.

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;
    }
}

Le dessous des supports de code spécifiant des limites dans un ordre quelconque (par exemple bound1 <= bound2 ou bound2 <= bound1). J'ai trouvée utile pour des valeurs de serrage calculées à partir des équations linéaires (y=mx+b) où la pente de la ligne peut être croissante ou décroissante.

Je sais: Le code se compose de cinq opérateurs d'expression conditionnelle super-vilains . La chose est, cela fonctionne , et les tests prouvent en dessous. Ne hésitez pas à ajouter entre parenthèses strictement inutiles si vous le désirez.

Vous pouvez facilement créer d'autres pour d'autres types de surcharges numériques et essentiellement copier / coller les tests.

Attention: La comparaison des nombres à virgule flottante n'est pas simple. Ce code ne met pas en œuvre des comparaisons double avec vigueur. Utilisez une bibliothèque de comparaison à virgule flottante pour remplacer les utilisations des opérateurs de comparaison.

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 / tests 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);
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top