سؤال

لدي الرمز التالي:

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 خطوط. هذا مطول تمامًا ، قبيح بعض الشيء ... أجرؤ على القول ، إنه تمامًا un-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))
هل كانت مفيدة؟

المحلول

هذا واضح جدا ، في الواقع. كثير من الناس يتعلمونها بسرعة. يمكنك استخدام تعليق لمساعدتهم.

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

نصائح أخرى

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

نرى numpy.clip:

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

العديد من الإجابات المثيرة للاهتمام هنا ، كل شيء عن نفسه ، باستثناء ... أيهما أسرع؟

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 لديه! ، استخدم python plain. النسخة numpy ، ربما ليس من المستغرب ، أبطأ الكثير. ربما لأنه يبحث عن المصفوفات ، حيث تطلب الإصدارات الأخرى حججها.

التسلسل max() و min() معا هو المصطلح الطبيعي الذي رأيته. إذا وجدت صعوبة في القراءة ، فاكتب وظيفة مساعد لتغليف العملية:

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

مهما حدث للغة الحبيبة القابلة للقراءة؟ :-)

على محمل الجد ، فقط اجعلها وظيفة:

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)

إذا أردت ذلك ، يمكنك حتى جعل قائمة Min/Max بحيث تبدو أكثر "نقية من الناحية الرياضية":

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

هذا يبدو أكثر بيثونيا بالنسبة لي:

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

إذا كان الكود الخاص بك يبدو غير عملي ، فقد تساعد الوظيفة:

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

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

تجنب كتابة وظائف لمثل هذه المهام الصغيرة ، إلا إذا قمت بتطبيقها في كثير من الأحيان ، لأنها ستشكل الرمز الخاص بك.

للقيم الفردية:

min(clamp_max, max(clamp_min, value))

لقوائم القيم:

map(lambda x: min(clamp_max, max(clamp_min, x)), values)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top