कुछ सीमा तक पूर्णांक को कैसे जकड़ें?


92

मेरे पास निम्नलिखित कोड हैं:

new_index = index + offset
if new_index < 0:
    new_index = 0
if new_index >= len(mylist):
    new_index = len(mylist) - 1
return mylist[new_index]

असल में, मैं एक नए सूचकांक की गणना करता हूं और सूची से कुछ तत्व खोजने के लिए इसका उपयोग करता हूं। यह सुनिश्चित करने के लिए कि सूचकांक सूची की सीमा के अंदर है, मुझे उन 2 ifकथनों को 4 पंक्तियों में लिखने की आवश्यकता है । यह काफी वाचाल है, थोड़ा बदसूरत है ... हिम्मत मैं कहता हूं, यह काफी अन-पाइथोनिक है

क्या कोई अन्य सरल और अधिक कॉम्पैक्ट समाधान है? (और अधिक pythonic )

हां, मुझे पता है कि मैं if elseएक पंक्ति में उपयोग कर सकता हूं , लेकिन यह पठनीय नहीं है:

new_index = 0 if new_index < 0 else len(mylist) - 1 if new_index >= len(mylist) else new_index

मुझे यह भी पता है कि मैं चेन कर सकता हूं max()और min()साथ में। यह अधिक कॉम्पैक्ट है, लेकिन मुझे लगता है कि यह थोड़े अस्पष्ट है, अगर मुझे यह गलत लगता है, तो कीड़े ढूंढना अधिक कठिन है। दूसरे शब्दों में, मुझे यह बहुत सीधा नहीं लगता।

new_index = max(0, min(new_index, len(mylist)-1))

2
यदि यह "थोड़े अस्पष्ट" लगता है, तो इससे एक समारोह बनाएं?
सांता

1
हाँ, मैं एक फ़ंक्शन लिख सकता हूं, लेकिन यह बात नहीं है। सवाल यह है कि इसे कैसे लागू किया जाए (या तो इनलाइन या किसी फंक्शन में)।
डेनिल्सन सा मैया

clamp = lambda value, minv, maxv: max(min(value, maxv), minv)Arma.sourceforge.net/docs.html#clamp
Dima Tisnek

जवाबों:


119

यह वास्तव में बहुत स्पष्ट है। कई लोग इसे जल्दी सीखते हैं। आप उनकी मदद करने के लिए एक टिप्पणी का उपयोग कर सकते हैं।

new_index = max(0, min(new_index, len(mylist)-1))

12
हालांकि मुझे लगता है कि यह उतना ही आकर्षक नहीं है जितना यह होना चाहिए, लेकिन मुझे यह भी लगता है कि यह अब तक का सबसे अच्छा समाधान है।
डेनिल्सन सा मैया

49
def clamp(n, smallest, largest): return max(smallest, min(n, largest))
सीएसएल

3
@ आईसीएल फोल्क्स हमेशा इन छोटे सहायक कार्यों को प्रदान करते हैं, लेकिन मुझे कभी नहीं पता है कि उन्हें कहां रखा जाए। helperFunctions.py? एक अलग मॉड्यूल? क्या होगा अगर यह पूरी तरह से अलग चीजों के लिए विभिन्न "सहायक कार्यों" से अटे पड़े हो?
मतीन उल्हाक

1
मुझे पता नहीं है, लेकिन अगर आप उनमें से बहुत कुछ इकट्ठा करते हैं और उन्हें समझदार मॉड्यूल में वर्गीकृत करते हैं, तो GitHub पर क्यों नहीं डालते हैं और उसमें से एक PyPi पैकेज बनाते हैं? शायद लोकप्रिय हो जाएगा।
सीएसएल

@ मतेनउलहकutils.py
15

85
sorted((minval, value, maxval))[1]

उदाहरण के लिए:

>>> minval=3
>>> maxval=7
>>> for value in range(10):
...   print sorted((minval, value, maxval))[1]
... 
3
3
3
3
4
5
6
7
7
7

10
sorted()बिल्ट-इन के रचनात्मक उपयोग के लिए +1 । बहुत कॉम्पैक्ट है, लेकिन यह केवल थोड़ा अस्पष्ट है। वैसे भी, अन्य रचनात्मक समाधानों को देखना हमेशा अच्छा होता है!
डेनिलसन सा मायिया

10
बहुत रचनात्मक, और वास्तव में min(max())निर्माण के रूप में उपवास के बारे में । इस मामले में बहुत तेजी से कि संख्या सीमा में है और स्वैप की जरूरत नहीं है।
किंडल

40

कई दिलचस्प जवाब यहाँ, सभी के बारे में एक ही है, सिवाय ... जो एक तेजी से है?

import numpy
np_clip = numpy.clip
mm_clip = lambda x, l, u: max(l, min(u, x))
s_clip = lambda x, l, u: sorted((x, l, u))[1]
py_clip = lambda x, l, u: l if x < l else u if x > u else x
>>> import random
>>> rrange = random.randrange
>>> %timeit mm_clip(rrange(100), 10, 90)
1000000 loops, best of 3: 1.02 µs per loop

>>> %timeit s_clip(rrange(100), 10, 90)
1000000 loops, best of 3: 1.21 µs per loop

>>> %timeit np_clip(rrange(100), 10, 90)
100000 loops, best of 3: 6.12 µs per loop

>>> %timeit py_clip(rrange(100), 10, 90)
1000000 loops, best of 3: 783 ns per loop

paxdiablo यह है!, सादे राजभाषा 'अजगर का उपयोग करें। सुन्न संस्करण, शायद आश्चर्यजनक रूप से नहीं है, बहुत से सबसे धीमा। संभवतः क्योंकि यह सरणियों की तलाश में है, जहां अन्य संस्करण सिर्फ अपने तर्क देते हैं।


7
@LenarHoyt यह आश्चर्य की बात नहीं है, यह देखते हुए कि नम्पी के प्रदर्शन को बड़े सरणियों के आसपास डिज़ाइन किया गया है, न कि एकल संख्या। इसके अलावा, पहले पूर्णांक को एक आंतरिक डेटाटाइप में बदलना पड़ता है और चूंकि यह कई अलग-अलग प्रकार के इनपुट स्वीकार करता है, इसलिए संभवतः यह पता लगाने में काफी समय लगता है कि इनपुट किस प्रकार का है और इसे किस रूप में रूपांतरित करना है। यदि आप इसे एक सरणी (अधिमानतः एक सूची या टपल नहीं है, जो इसे कई हजारों मानों को पहले परिवर्तित करना है) खिलाते हैं तो आप बेहतर प्रदर्शन करेंगे।
ब्लबरडाइब्लूब

पायथन परिमाण धीमे के तीन क्रम हैं। 783 एनएस = 783,000 7s। मैंने अतीत में भी यही गलती की है। अंकन सूक्ष्म है।
डस्टिन एंड्रयूज

5
@DustinAndrews आपको वह पीछे की तरफ मिल गया है। 1 ns 10 ^ -6 सेकंड है, 1 एनएस 10 ^ -9 सेकंड है। अजगर उदाहरण 0.784 µs में 1 लूप पूरा करता है। या कम से कम, यह उस मशीन पर किया था जिस पर मैंने इसका परीक्षण किया था। यह माइक्रोबेनमार्क किसी अन्य माइक्रोबेनमार्क के रूप में उपयोगी है; यह आपको वास्तव में बुरे विचारों से दूर कर सकता है, लेकिन संभवतः आपको उपयोगी कोड लिखने के लिए वास्तव में सबसे तेज़ तरीका खोजने में मदद नहीं करेगा ।
22

फ़ंक्शन के कॉल पर एक मामूली ओवरहेड है। मैंने बेंचमार्क नहीं किया है, लेकिन यह काफी संभव है mm_clipऔर py_clipअगर आप PyPy जैसे JIT कंपाइलर का उपयोग करते हैं तो यह भी उतना ही तेज़ होगा। पूर्व को छोड़कर अधिक पठनीय है, और पाइथन के दर्शन में पठनीयता अधिक महत्वपूर्ण है, क्योंकि अधिकांश समय मामूली प्रदर्शन लाभ होता है।
हाईस्टेकर

@DustinAndrews मैं आपकी तथ्यात्मक रूप से गलत टिप्पणी को हटाने की सलाह देता हूं क्योंकि आपने इसे पीछे की तरफ किया था।
एक्यूमेनस

38

देखें numpy.clip :

index = numpy.clip(index, 0, len(my_list) - 1)

डॉक्स का पहला पैरामीटर clipहै a, "एक सरणी जिसमें क्लिप के लिए तत्व" है। इसलिए आपको लिखना होगा numpy.clip([index], …, नहीं numpy.clip(index, …
रोरी ओ'केन

13
@ रोरीओकेन: क्या आपने इसकी कोशिश की?
नील जी

1
पंडों ने श्रृंखला और डेटाफ़्रेम और पैनलों पर भी इसकी अनुमति दी है।
नूर वुल्फ

17

जंजीर max()और min()एक साथ मैंने देखा है सामान्य मुहावरा है। यदि आपको पढ़ना मुश्किल लगता है, तो ऑपरेशन को एनकैप्सुलेट करने के लिए एक सहायक फ़ंक्शन लिखें:

def clamp(minimum, x, maximum):
    return max(minimum, min(x, maximum))

14

जो कुछ भी मेरे प्यारे पठनीय पायथन भाषा का हुआ? :-)

गंभीरता से, बस इसे एक समारोह बनाओ:

def addInRange(val, add, minval, maxval):
    newval = val + add
    if newval < minval: return minval
    if newval > maxval: return maxval
    return newval

तो बस इसे कुछ इस तरह से कॉल करें:

val = addInRange(val, 7, 0, 42)

या एक सरल, अधिक लचीला, समाधान जहां आप स्वयं गणना करते हैं:

def restrict(val, minval, maxval):
    if val < minval: return minval
    if val > maxval: return maxval
    return val

x = restrict(x+10, 0, 42)

यदि आप चाहते हैं, तो आप न्यूनतम / अधिकतम सूची भी बना सकते हैं ताकि यह अधिक "गणितीय रूप से शुद्ध" दिखे।

x = restrict(val+7, [0, 42])

6
इसे एक फंक्शन में लाना ठीक है (और सलाह दी जाती है, यदि आप इसे बहुत कुछ कर रहे हैं), लेकिन मुझे लगता है minऔर maxसशर्त का एक गुच्छा की तुलना में बहुत स्पष्ट है। (मुझे नहीं पता कि क्या addहै - बस कहना है clamp(val + 7, 0, 42)।)
ग्लेन मेनार्ड

1
@GlennMaynard। मुझे यकीन नहीं है कि मैं सहमत हो सकता हूं कि न्यूनतम और अधिकतम क्लीनर हैं। उनका उपयोग करने का पूरा बिंदु एक पंक्ति में अधिक सामान रखने में सक्षम होना है, प्रभावी रूप से कोड को कम सुपाठ्य बनाना है।
मैड फिजिसिस्ट

9

यह मुझे और अधिक अजीब लगता है:

>>> def clip(val, min_, max_):
...     return min_ if val < min_ else max_ if val > max_ else val

कुछ परीक्षण:

>>> clip(5, 2, 7)
5
>>> clip(1, 2, 7)
2
>>> clip(8, 2, 7)
7

7

यदि आपका कोड बहुत ही अस्पष्ट है, तो एक फ़ंक्शन मदद कर सकता है:

def clamp(minvalue, value, maxvalue):
    return max(minvalue, min(value, maxvalue))

new_index = clamp(0, new_index, len(mylist)-1)

2

ऐसे छोटे कार्यों के लिए लेखन कार्य से बचें, जब तक कि आप उन्हें अक्सर लागू नहीं करते, क्योंकि यह आपके कोड को अव्यवस्थित कर देगा।

व्यक्तिगत मूल्यों के लिए:

min(clamp_max, max(clamp_min, value))

मूल्यों की सूची के लिए:

map(lambda x: min(clamp_max, max(clamp_min, x)), values)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.