Dove posso trovare la funzione “pinza” in .NET?
Domanda
Vorrei fissare un x
valore ad una gamma [a, b]
:
x = (x < a) ? a : ((x > b) ? b : x);
Questo è abbastanza semplice. Ma non vedo una funzione di "pinza" nella libreria di classi -. Almeno non in System.Math
(Per l'ignaro a "pinza" un valore è quello di assicurarsi che si trova tra alcuni valori massimi e minimi. Se è superiore al valore massimo, allora è sostituito dal massimo, ecc.)
Soluzione
Si potrebbe scrivere un metodo di estensione:
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: metodi di estensione vanno in classi statiche - dal momento che questo è piuttosto una funzione di basso livello, probabilmente dovrebbe andare in qualche namespace principale nel progetto. È quindi possibile utilizzare il metodo in qualsiasi file di codice che contiene una direttiva using per lo spazio dei nomi per es.
using Core.ExtensionMethods
int i = 4.Clamp(1, 3);
.NET Nucleo 2.0
A partire da .NET 2.0 Nucleo System.Math
ora ha una Clamp
metodo che può essere utilizzato al posto:
using System;
int i = Math.Clamp(4, 1, 3);
Altri suggerimenti
Prova:
public static int Clamp(int value, int min, int max)
{
return (value < min) ? min : (value > max) ? max : value;
}
Basta usare Math.Min
e Math.Max
:
x = Math.Min(Math.Max(x, a), b);
non è uno, ma non è troppo difficile fare uno. Ho trovato uno qui: morsetto
Si tratta di:
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;
}
E può essere usato come:
int i = Clamp(12, 10, 0); -> i == 10
double d = Clamp(4.5, 10.0, 0.0); -> d == 4.5
Non è uno nel namespace System.Math
http://msdn.microsoft.com/en-us/ biblioteca / system.math_members.aspx
C'è una classe MathHelper dove è disponibile per lo studio XNA gioco se che sembra essere quello che state facendo:
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;
}
Differenze:
- Nome metodo utilizza l'appropriato tempo verbale (
ed
) a (ulteriore) indicano che il valore non è bloccato sul posto, e che, invece, viene restituito un nuovo valore (Vedere @ di JimBalter commenti ). - Fa appropriata
null check
su tutti gli ingressi (Vedere @ di JeppeStigNielsen commenti ). - Swap
min
emax
semin > max
(Vedere @ di JeppeStigNielsen commenti ).
Limitazioni:
Nessun morsetti unilaterale. Se max
è NaN
, restituisce sempre NaN
(See commento di Herman).
Utilizzando le risposte precedenti, ho condensato giù al di sotto del codice per le mie esigenze. Questo permetterà anche di bloccarlo su un numero solo per la sua minima o massima.
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;
}
}
Il sotto supporti codice specificano limiti in qualsiasi ordine (cioè bound1 <= bound2
, o bound2 <= bound1
). Ho trovato questo utile per i valori calcolati dalle equazioni lineari (y=mx+b
) in cui la pendenza della linea può essere crescente o decrescente serraggio.
Lo so: il codice è costituito da cinque super-brutto operatori espressione condizionale . La cosa è, funziona , ed i test sotto lo dimostrano. Sentitevi liberi di aggiungere parentesi rigorosamente inutili se lo desiderano.
Si può facilmente creare altri sovraccarichi per altri tipi numerici e fondamentalmente copia / incolla il test.
Attenzione: Confrontando i numeri in virgola mobile non è semplice. Questo codice non implementa confronti double
robusto. Utilizzare una libreria di confronto in virgola mobile per sostituire gli usi di operatori di confronto.
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 / test 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);
}
}