2014-09-04 4 views
2

Я хотел бы протестировать несколько неравенств сразу, т.е.Multiple неравенства (а <Ь <с ...) с потенциально отсутствующим значением

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

что хорошо, когда все значения присутствуют. Однако иногда числовое значение одной или нескольких переменных, которые нужно сравнить, может отсутствовать/неизвестно; правильное поведение в моем контексте состоит в том, чтобы предположить, что соответствующее неравенство выполнено. Скажем, я присвоить специальное значение None, когда значение неизвестно: поведение, я хочу от < оператора (или альтернатива) является:

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

Так что я хочу, чтобы получить True, если одна переменная действительно меньше, чем другой, или если одна переменная отсутствует (принимает какое-либо определенное заранее определенное нечисловое значение) или если обе переменные отсутствуют, и я хочу иметь возможность сопоставлять сравнения друг с другом, т.е. a < b < c < ...
Я также хотел бы сделайте это с <=, а также <.
Благодаря

+0

Я не думаю, что вы можете сделать это надежно при сравнении - вы получите значение, которое сравнивается больше чем что-либо и меньше всего в одно и то же время. Вместо этого я определял бы функцию, которая принимает итерабельность значений, и возвращает True, если значения None-None упорядочены. – Kos

+5

, если a равно 3, b - None, а c равно 1, должен ли 'a Kevin

+1

И Python 3 отклоняет 'a

ответ

5

Вы хотите проверить, если ваша последовательность - бар на неопределенные значения - в порядке возрастания:

import operator 

def isAscending(strictly, *seq): 
    cmp_op = operator.lt if stricly 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 орфографии, а также использовать операторы сравнения, как предложено.

+1

Вы также можете передать сравнение для использования в качестве другого параметра, например. 'operator.lt' или как лямбда. –

+1

Правописание nitpick: это должно быть «строго». – Kevin

2

Это выглядит как будто вы на самом деле пытается проверить, если ваши ценности являются уникальными и в отсортированном порядке, в котором можно было бы заменить на что-то вроде:

>>> 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: включая тайминги оно кажется, что функция, предложенная sebdelsol, еще быстрее

>>> %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 
+0

Что произойдет, если вы написали 'my_test ([1,0,3])'? ;) Измените его на 'v для v в l, если v не является None'. – flakes

+1

также рассмотрите возможность изменения' my_test (l) 'на' my_test (* l) '. Таким образом, вам не нужно явно указывать параметры в контейнере. т.е.) вы можете быть ближе к запросу OP 'my_test (a, b, c)' – flakes

0

У меня нет думаю, что у вас есть лучший вариант, чем определить функцию сравнения, которая делает сравнение, как вы хотите, а затем записать неравенство в

comp(a,b) and comp(b,c) and ... 
+0

... Это неправда Python. –

+0

@JoelCornett Woops, исправлено – HamHamJ

1

Вы можете создать свои собственные методы сравнения типа перегрузки (как в этом вопросе: python overloading operators)

Например

class N(object): 
    def __init__(self, value): 
     self.value = value 

    def __lt__(self, other): 
     return (self.value is None or self.value < other.value) 
    ... 


a = N(1); b = N(None); c = N(3) 
print a < b < c 
+0

не работает даже с вашим примером ... ogic только checs none в 1-ом значении. измените __th__ на: return (self.value - None или self.value Joop

+0

Я тоже думал об этом, но это не очень удобно. Возможно, это было бы немного менее непривлекательно, если бы вам не пришлось отводить каждый номер в этот класс, но все обходные пути, о которых я могу думать, более сложны, чем некоторые другие ответы. Итак, на балансе +0. – tripleee

1

Если у вас есть ваши значения в списке ([a, b, c]), вы можете отфильтровать из него значения None, соедините их с помощью zip(), примените оператор ко всем парам и посмотрите, все ли они удерживаются.

В коде:

import operator # For operator.lt, which is < ("less than") 

def mass_comparify(op, *args): 
    return all(op(a, b) for a, b in zip(args, args[1:]) 
       if a is not None and b is not None) 

print(mass_comparify(operator.lt, 1, None, 3)) # Prints True because 1 < 3 
0

Я не знаю, если это соответствует втирают, но вы можете использовать reduce:

>>> import operator 
>>> reduce(operator.__lt__, [1, None, 3]) 
True 
>>> reduce(operator.__lt__, [1, None, 0]) 
False 

или, гораздо более прочной, так как он явно игнорирует значения None:

>>> import operator 
>>> reduce(operator.__lt__, filter(None, [1, None, 3])) 
True 
>>> reduce(operator.__lt__, filter(None, [1, None, 0])) 
False 
Смежные вопросы