Home > Net >  See if index is contained within a slice object
See if index is contained within a slice object

Time:11-27

I have an enum like this:

class AgeCategory(Enum):
    Child = slice(None, 16)
    YoungAdult = slice(16, 25)
    ...
    Old = slice(85, None) 

It basically provides a range of ages (in years) which go in each category.

I would like a function to check which age range a certain value corresponds to. This was my idea:

def get_category(age: int) -> AgeCategory:
    for age_range in AgeCategory:
         if age in age_range.value #check if it's in the slice for that enum
             return age_range
    else:
        assert False, "unreachable"

However assert 5 in slice(1,10) fails. OFC I could do something like:

s: slice = age_range.value
if s.start <= age < s.stop: #bounds check
    return age_range

But that ignores the step argument and feels like reinventing the wheel a bit.


What's a pythonic way to express these age ranges? They are used as slices like this:

ya_data = np.sum(some_data[AgeCategory.YoungAdult])

CodePudding user response:

In your case it is not so much important, but this should be faster than iterating when working with large slices:

a_slice = slice(4, 15, 3)
def is_in_slice(a_slice, idx):
    if idx < a_slice.start or idx >= a_slice.stop:
        return False
    step = a_slice.step if a_slice.step else 1
    if (idx - a_slice.start) % step == 0:
        return True
    else:
        return False
    
test_array = np.where([is_in_slice(a_slice, idx) for idx in range(20)])[0]
print(test_array)
[ 4  7 10 13]

And test for very big slice:

a_big_slice = slice(0, 1_000_000_000_000, 5)
print(is_in_slice(a_big_slice, 999_000_000_005))
print(is_in_slice(a_big_slice, 999_000_000_004))
True
False

CodePudding user response:

With a sample slice:

In [321]: child=slice(None,16,4)

I was thinking of expanding it to a list or array. But arange can't handle the None:

In [323]: np.arange(child.start,child.stop,child.step)
Traceback (most recent call last):
  File "<ipython-input-323-b2d245f287ff>", line 1, in <module>
    np.arange(child.start,child.stop,child.step)
TypeError: unsupported operand type(s) for -: 'int' and 'NoneType'

np.r_ can. Here the numpy developers have gone to all the work of translating all the slice options:

In [324]: np.r_[child]
Out[324]: array([ 0,  4,  8, 12])
In [325]: 3 in _
Out[325]: False
In [327]: 4 in __
Out[327]: True

It may not be fastest, but appears to be most general purpose approach - with out a lot work on your part.

  • Related