2

Imagine you have a structured array, for example like this:

import numpy as np


a = np.array(
    [tuple([np.random.randint(100) for _ in range(3)]) for _ in range(100)], 
    dtype=[('var1', 'i4'), ('var2', 'i4'), ('var3', 'i4')]
)

Now I only want to access a specific subset / slice of this array. For example like this:

interval = (10, 30)
b = a[
    (a['var1'] >= interval[0]) & (a['var1'] <= interval[1])
]

So far so good. But what if I have a variable number of intervals corressponding to different variables? For example like this:

intervals = [('var1', 10, 30), ('var2', 20, 50)]

I cannot hardcode it because the amount of intervals changes while the program is running. but what I would like is something like this for an arbitrary number of intervals:

b = a[
    ((a[intervals[0][0]] >= intervals[0][1]) & (a[intervals[0][0]] <= intervals[0][2])) |
    ((a[intervals[1][0]] >= intervals[1][1]) & (a[intervals[1][0]] <= intervals[1][2]))
]

The only idea that I have had so far is using a for loop to go over the intervals and create a string that can then be excecuted using eval, but I don't really like this. Is there a better solution?

string = 'a[((a[intervals[0][0]] >= intervals[0][1]) & (a[intervals[0][0]] ' \
         '<= intervals[0][2]))'
for i in range(len(intervals[1:])):
    string += f' | \n((a[intervals[{i+1}][0]] >= intervals[{i+1}][1]) & ' \
              f'(a[intervals[{i+1}][0]] <= intervals[{i+1}][2]))'
string += ']'

b = eval(string)

2 Answers 2

2

You don't need to generate code for this problem. Use functools.reduce to apply the | operator on an unknown series of masks.

import operator
from functools import reduce

mask = reduce(
    operator.__or__,  # the `|` operator
    (
        ((a[var] >= lower) & (a[var] <= upper))
        for var, lower, upper in intervals  # arbitrary number of intervals
    )
)

b = a[mask]
Sign up to request clarification or add additional context in comments.

Comments

1

I'd put the conditions in a list of tuples, and bind them using a function and map, i.e.:

def fmask(tup):
  ix, low, up = tup
  return (a[ix] > low) & (a[ix] < up)

conds = [('var1', 10, 80), ('var2', 30, 40)]

a[np.logical_and(*map(fmask))]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.