I'm trying to process numerical input arguments for a function. Users can mix ints, floats, and "array-like" things of ints and float, as long as they are all length=1 or the same length>1.
Now I convert them as follows:
convert to float convert to np.ndarray; dtype==float
---------------- -----------------------------------
float
int
np.float64
range object resulting in len == 1 range object resulting in len > 1
len==1 list or tuple of int or float len > 1 list or tuple of ints & floats
len==1 np.ndarray of dtype np.int or np.float len > 1 np.ndarray of dtype np.int or np.float
then test all resulting arrays to make sure they are the same length. If so, I return a list containing floats and arrays. If not, return None
.
I want to avoid up-conversion of booleans and small byte-length ints.
The script below appears to do what I want by brute force testing, but I wonder if there is a better way?
Desired behaviors:
fixem(some_bad_things)
returnsNone
fixem(all_good_things)
returns[42.0, 3.14, 3.141592653589793, 2.718281828459045, 3.0, 42.0, 3.0, 42.0, array([1. , 2.3, 2. ]), array([3.14, 1. , 4. ]), array([1., 2., 2.]), array([3., 1., 4.]), array([0., 1., 2.]), array([0, 1, 2])]
and
sum(fixem(all_good_things))
returnsarray([149.13987448 149.29987448 156.99987448])
def fixit(x):
result = None
if type(x) in (int, float, np.float64):
result = float(x)
elif type(x) == range:
y = list(x)
if all([type(q) in (int, float) for q in y]):
if len(y) == 1:
result = float(y[0])
elif len(y) > 1:
result = np.array(y)
elif type(x) in (tuple, list) and all([type(q) in (int, float) for q in x]):
y = np.array(x)
if y.dtype in (int, float):
if len(y) == 1:
result = float(y[0])
elif len(y) > 1:
result = y.astype(float)
elif (type(x) == np.ndarray and len(x.shape) == 1 and
x.dtype in (np.int, np.float)):
if len(x) == 1:
result = float(x[0])
elif len(x) > 1:
result = x.astype(float)
return result
def fixem(things):
final = None
results = [fixit(thing) for thing in things]
floats = [r for r in results if type(r) is float]
arrays = [r for r in results if type(r) is np.ndarray]
others = [r for r in results if type(r) not in (float, np.ndarray)]
if len(others) == 0:
if len(arrays) == 0 or len(set([len(a) for a in arrays]))==1: # none or all same length
final = floats + arrays
return final
import numpy as np
some_bad_things = ('123', False, None, True, 42, 3.14, np.pi, np.exp(1),
[1, 2.3, 2], (3.14, 1, 4), [1, 2, 2], (3, 1, 4),
(3,), [42], (3.,), [42.], np.array([True, False]),
np.array([False]), np.array(False), np.array('xyz'),
np.array(42), np.array(42.), np.arange(3.), range(3))
all_good_things = (42, 3.14, np.pi, np.exp(1), [1, 2.3, 2], (3.14, 1, 4),
[1, 2, 2], (3, 1, 4), (3,), [42], (3.,), [42.],
np.arange(3.), range(3))
for i, things in enumerate((some_bad_things, all_good_things)):
print(i, fixem(things))
print(sum(fixem(all_good_things))) # confirm