【问题标题】:Multiple inequality (a < b < c...) with potentially missing value具有潜在缺失值的多重不等式 (a < b < c...)
【发布时间】:2014-09-04 12:24:18
【问题描述】:

我想一次测试多个不等式,即

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

当所有值都存在时,这很好。然而,有时要比较的一个或多个变量的数值可能会丢失/未知;在我的上下文中,正确的行为是假设相关的不等式得到满足。假设我在值未知时分配了特殊值 None:我希望 &lt; 运算符(或替代方法)的行为是:

>>> 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 &lt; b &lt; c &lt; ...
我也想用&lt;=&lt; 来做这件事。
谢谢

【问题讨论】:

  • 我不认为你可以通过比较可靠地做到这一点 - 你会获得一个同时比较大于任何东西和小于任何东西的值。相反,我会定义一个函数,该函数接受一个可迭代的值并在非 None 值被排序时返回 True。
  • 如果a为3,b为None,c为1,即使a不小于c,a &lt; b &lt; c是否应该返回True?
  • 如果使用 None 值,Python 3 将完全拒绝 a &lt; b &lt; c
  • @Kevin 是的,抱歉应该明确表示。由于正确解释了接受的答案,我基本上想排除未定义的值,只比较剩下的值。

标签: python missing-data inequalities


【解决方案1】:

您想测试您的序列(除了未定义的值)是否按升序排列:

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 ?

编辑拼写,并按照建议使用比较运算符。

【讨论】:

  • 您也可以传递比较以用作另一个参数,例如operator.lt 或作为 lambda。
  • 拼写挑剔:应该是“严格”。
  • 编写一个其中一个参数几乎总是硬编码常量的函数通常是糟糕的设计。 isAscending 应该是两个函数:is_ascendingis_strictly_ascending
【解决方案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

编辑:包括时间,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

【讨论】:

  • 如果你写my_test([1,0,3])会发生什么? ;) 将其更改为 v for v in l if not v is None
  • 还可以考虑将my_test(l) 更改为my_test(*l)。这样您就不必在容器中显式转换参数。即)你可以更接近OP的要求my_test(a, b, c)
【解决方案3】:

您可以创建自己的类型重载比较方法(如本问题: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

【讨论】:

  • 即使在您的示例中也不起作用... ogic 仅在第一个值中检查 none。将 th 更改为:return (self.value is None or self.value
  • 我也想建议这个,但它不是很有用。如果您不必将每个数字都转换为此类,也许它会稍微不那么吸引人,但我能想到的所有解决方法都比其他一些答案更复杂。所以总的来说,+0。
【解决方案4】:

如果您的值在列表中 ([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

【讨论】:

    【解决方案5】:

    我认为您没有比定义一个比较函数更好的选择,该函数可以根据需要进行比较,然后将不等式写为

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

    【讨论】:

    • ... 这不是有效的 Python。
    • @JoelCornett Woops,已修复
    【解决方案6】:

    我不知道它是否完美,但你可以使用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
    

    【讨论】:

      猜你喜欢
      • 2011-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-28
      • 2015-06-12
      • 1970-01-01
      • 1970-01-01
      • 2013-11-07
      相关资源
      最近更新 更多