Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple inequality (a < b < c...) with potentially missing value

I would like to test multiple inequalities at once, i.e.

if (a < b < c < ...)

which is fine when all the values are present. However sometimes the numeric value of one or more of the variables to be compared may be missing/unknown; the correct behaviour in my context is to assume the associated inequality is satisfied. Let's say I assign the special value None when the value is unknown: the behaviour I want from the < operator (or an alternative) is:

>>> a = 1; b = 2; c = 3
>>> a < b < c # this works fine, obviously
True 
>>> b = None
>>> a < b < c # would like this to return True
False

So I want to get True if one variable is truly smaller than the other, or if one variable is missing (takes any particular pre-decided non-numerical value), or if both variables are missing, and I want to be able to string the comparisons together one go i.e. a < b < c < ...
I would also like to do this with <= as well as <.
Thanks

like image 611
ChrisW Avatar asked Feb 14 '26 09:02

ChrisW


2 Answers

You want to test if your sequence – bar the undefined values – is in ascending order:

import operator

def isAscending(strictly, *seq):
    cmp_op = operator.lt if strictly else operator.le 
    seq = [e for e in seq if e is not None]
    return all(cmp_op(a, b) for a, b in zip(seq, seq[1:]))

a, b, c = 1, None, 2
print isAscending(True, a, b, c) # strictly ascending ?

Edited for spelling, and to use comparison operators as suggested.

like image 51
sebdelsol Avatar answered Feb 15 '26 22:02

sebdelsol


This looks like you are actually trying to test if your values are unique and in sorted order which could be replaced by something like:

>>> def my_test(l):
>>>     filt_l = [v for v in l if not v is None]
>>>     return (sorted(filt_l) == filt_l) and (len(filt_l) == len(set(filt_l)))

>>> my_test([1,2,3])
True 
>>> my_test([1,None,3])
True 
>>> my_test([1,4,3])
False
>>> my_test([1,1,3])
False

Edit: including timings it seems that the function suggested by sebdelsol is even faster

>>> %timeit isAscending([int(1000*random.random()) for i in xrange(10000)])
100 loops, best of 3: 3.44 ms per loop

>>> %timeit my_test([int(1000*random.random()) for i in xrange(10000)])
100 loops, best of 3: 5.67 ms per loop
like image 25
greole Avatar answered Feb 15 '26 22:02

greole



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!