मैं .NET में "क्लैंप" फ़ंक्शन कहाँ पा सकता हूं?


92

मैं एक मूल्य xको एक सीमा में जकड़ना चाहूंगा [a, b]:

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

यह काफी बुनियादी है। लेकिन मुझे क्लास लाइब्रेरी में एक फंक्शन "क्लैम्प" नहीं दिख रहा है - कम से कम अंदर नहीं System.Math

(अनजान के लिए "दबाना" एक मूल्य यह सुनिश्चित करने के लिए है कि यह कुछ अधिकतम और न्यूनतम मूल्यों के बीच है। यदि यह अधिकतम मूल्य से अधिक है, तो इसे अधिकतम द्वारा बदल दिया जाता है, आदि)


2
@ डनविल: कोई "C # क्लास लाइब्रेरी" नहीं है। आपका मतलब है ".NET .NET फ्रेमवर्क"।
जॉन सॉन्डर्स

1
अभी भी C # 7.1 जैसा कुछ नहीं है?
जॉइस

1
@ जॉनसन मुझे विश्वास नहीं है कि यह कड़ाई से सच है stackoverflow.com/questions/807880/…
एडम नाइलर

अगर मैंने पूछा कि दुनिया के हर एक अंग्रेजी बोलने वाले प्रोग्रामर को "लिमिट" कैसे करना है, तो मुझे तुरंत पता चल जाएगा कि मेरा क्या मतलब है। सबसे अधिक संभावना है कि हर प्रोग्रामर को पता होगा। व्यापार में 30+ वर्ष के बाद मुझे यह पता लगाना था कि आज "क्लैंप" का क्या मतलब है। "निर्भरता इंजेक्शन" के समान - "पैरामीटरेशन" एक ऐसी स्पष्ट बात है जिस पर किसी ने कभी कोई पुस्तक नहीं लिखी।
बॉब

@ कुछ शब्दों के ऐतिहासिक, अच्छे अर्थ हैं। क्लैंप उनमें से एक है। en.wikipedia.org/wiki/Clamping_(graphics) या khronos.org/registry/OpenGL-Refpages/gl4/html/clamp.xhtml या docs.microsoft.com/en.us/windows/win32/direct3dhlsl/… "सीमा" "भ्रामक होगा, खासकर कि" सीमा "का गणित में पहले से ही एक अलग अर्थ है।
कालस

जवाबों:


135

आप एक विस्तार विधि लिख सकते हैं:

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 कोर 2.0

.NET Core 2.0 के साथ System.Mathअब एक Clampविधि है जिसका उपयोग इसके बजाय किया जा सकता है:

using System;

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

1
मैं इसे कहां रखूंगा और तुलना (धीमे प्रकार के) के साथ तुलना करने से तुलना कर रहा हूं?
Danvil

1
एक स्थिर वर्ग में, और .NET फ्रेमवर्क (मोनो, कॉम्पैक्ट, आदि के बारे में निश्चित नहीं) में, जेनेरिक को टाइप के लिए recompiled किया जाना चाहिए, और इनबिल्ट इनबिल्ट, इसलिए कोई प्रदर्शन जुर्माना नहीं।
रॉबर्ट फ्रेजर

1
@ फारसीयर जब तक यह अल्ट्रा परफॉर्मेंस सेंसिटिव कोड नहीं है, तब तक आप ऐसा करके कोई सार्थक प्रदर्शन हासिल करने की संभावना नहीं रखते हैं। जेनेरिक होना कुछ माइक्रोसेकंड बचाने से ज्यादा उपयोगी है।
MgSam

4
जेनेरिक संस्करण में बाधा डालने के बारे में अच्छी बात यह IComparableहै कि कोई बॉक्सिंग नहीं होती है। यह बहुत तेज दौड़ना चाहिए। याद रखें कि doubleऔर float, CompareToविधि कुल आदेश से मेल खाती है , जहां NaNसभी अन्य मूल्यों से कम है, जिसमें शामिल हैं NegativeInfinity। तो यह <ऑपरेटर के बराबर नहीं है । यदि आप <फ्लोटिंग-पॉइंट प्रकार के साथ उपयोग करते हैं, तो आपको यह भी विचार करना होगा कि इलाज कैसे किया जाए NaN। यह अन्य संख्यात्मक प्रकारों के लिए प्रासंगिक नहीं है।
जेपी स्टिग नीलसन 20

1
आपको इस बात पर विचार करने की आवश्यकता होगी कि NaNकिसी भी स्थिति में इलाज कैसे किया जाए । के साथ <और >उत्पादन NaNऔर उपयोग के NaNलिए संस्करण होगाmin या maxप्रभावी रूप से एक तरफा क्लैंप होगा। यदि ऐसा है तो CompareToइसके साथ हमेशा वापसी होगी । NaNmaxNaN
हरमन

29

बस उपयोग Math.Minऔर Math.Max:

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

इसका अनुवाद int a0 = x > a ? x : a; return a0 < b ? a0 : b(हालांकि सही परिणाम देता है) बिल्कुल आदर्श नहीं है।
श्री स्मिथ

12
और यही वजह है कि?
d7samurai

4
@ d7samurai यदि हम जानते हैं कि मिन <= अधिकतम है, Math.Min(Math.Max(x, min), max)तो एक्स <मिनट की तुलना में एक से अधिक तुलना में परिणाम होता है।
जिम बाल्टर

@JimBalter, सिद्धांत रूप में यह सच है। यदि आप यह देखते हैं कि तुलना () आम तौर पर कैसे लागू की जाती है, तो स्वीकृत उत्तर 6 तुलना तक ले सकता है। मैं नहीं जानता, हालांकि, कंपाइलर काफी स्मार्ट है और तुलना () को रेखांकित करता है और शानदार तुलना को हटा देता है।
क्विनमार

1
यह उन मामलों के लिए अच्छा है, जब आपको केवल एक बार करने की आवश्यकता होती है, तो इसके लिए पूरी तरह से नया कार्य एक ओवरकिल की तरह लगता है।
फोस

26

प्रयत्न:

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

6
ओह! उन बदसूरत निरर्थक कोष्ठक! यदि आप डबल टर्नरी ऑपरेटरों के साथ एक दुष्ट प्रतिभा होने जा रहे हैं, तो कम से कम इसे ठीक से करें और उन लोगों से भी छुटकारा पाएं! 😂
XenoRo

8
@ XenoRo "बेमानी" कोष्ठक हैं जो इसे पठनीय बनाता है।
क्लीयर

2
@ क्लेनर - 1) यदि आप पठनीयता के लिए जा रहे हैं, तो डबल टर्नरी से बचा जाएगा और इसके बजाय IF ब्लॉक का उपयोग किया जाएगा। 2) आप मजाक नहीं करते, क्या आप? XD
XenoRo

13

वहाँ एक नहीं है, लेकिन यह एक बनाने के लिए बहुत मुश्किल नहीं है। मुझे यहां एक मिला: क्लैंप

यह है:

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

यह समाधान स्वीकृत एक से बेहतर है। कोई अस्पष्टता नहीं।
aggsol

6
@CodeClown मान> अधिकतम, और उल्टे तर्क क्रम (और वस्तुतः गारंटी देता है) बग्स में इस समाधान का एक अनावश्यक तुलना में परिणाम होता है। मैं नहीं जानता कि आप किस अस्पष्टता से बचते हैं।
जिम बेल्टर

विरासत Math.Clamp कार्यान्वयन के साथ स्थिरता के लिए, न्यूनतम / अधिकतम मापदंडों के क्रम को बदलने की सलाह देते हैं:Clamp(T value, T min, T max)
josh पोली


4

जहां संभव हो, टिप्पणियों के मुद्दों और चिंताओं के साथ ली के समाधान को साझा करना:

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

अंतर:

सीमाएँ: कोई एकतरफा क्लैंप नहीं। यदि maxहै NaN, तो हमेशा लौटते हैं NaN(देखें हरमन की टिप्पणी )।


एक और सीमा nameofC # 5 या उससे नीचे के लिए काम नहीं करती है।
RoLYroLLs

0

पिछले उत्तरों का उपयोग करते हुए, मैंने अपनी आवश्यकताओं के लिए इसे नीचे दिए गए कोड तक सीमित कर दिया। यह आपको केवल इसके न्यूनतम या अधिकतम द्वारा एक संख्या को क्लैंप करने की अनुमति देगा।

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

क्यों नहीं return value.ClampedMinimum(min).ClampedMaximum(max);?
हेनरिक

0

नीचे दिया गया कोड किसी भी क्रम में सीमा निर्दिष्ट करने का समर्थन करता है (यानी 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 / फ्लुएंटसॉर्शन परीक्षण:

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

0

अगर मैं [मिनट, अधिकतम] में एक तर्क की श्रेणी को मान्य करना चाहता हूं, तो मैं निम्नलिखित काम वर्ग का उपयोग करता हूं:

public class RangeLimit<T> where T : IComparable<T>
{
    public T Min { get; }
    public T Max { get; }
    public RangeLimit(T min, T max)
    {
        if (min.CompareTo(max) > 0)
            throw new InvalidOperationException("invalid range");
        Min = min;
        Max = max;
    }

    public void Validate(T param)
    {
        if (param.CompareTo(Min) < 0 || param.CompareTo(Max) > 0)
            throw new InvalidOperationException("invalid argument");
    }

    public T Clamp(T param) => param.CompareTo(Min) < 0 ? Min : param.CompareTo(Max) > 0 ? Max : param;
}

वर्ग सभी ऑब्जेक्ट के लिए काम करता है जो हैं IComparable। मैं एक निश्चित सीमा के साथ एक उदाहरण बनाता हूं:

RangeLimit<int> range = new RangeLimit<int>(0, 100);

मैं या तो एक तर्क को मान्य करता हूं

range.Validate(value);

या श्रेणी के तर्क को दबाना:

var v = range.Validate(value);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.