python实现' if x in y where x.a tr == val '的方法



我有一个类,它将多项式表示为项的集合,其中每个项有一个系数和一个指数。我正在研究该类的__add__方法,我想知道最有效的方法是什么:

def __add__(self, other):
    new_terms = []
    for term in self.terms:
        if there is a term in other with an exponent == term.exponent
            new_terms.append(Term(term.coef + other_term.coef, term.exponent))

我突然想到我正在找这样的东西:

if x in y where x.attr == val

或者在我的特殊情况下:

if x in other where x.exponent == term.exponent

这样的东西存在吗?

您需要在执行包含检查之前过滤列表。正如tobias_k所建议的,您可以构建一个新的列表,例如

[x for x in other if x.exponent == term.exponent]

这在if语句中直接起作用,因为空列表是False:

if [x for x in other if x.exponent == term.exponent]:

但是这做了一些浪费的工作,因为它a)必须构造一个新的列表,b)一旦找到结果就不会短路。更好的方法是在生成器表达式中使用相同的语法:

(True for x in other if x.exponent == term.exponent)

您可以在if语句中类似地使用它,但不会做浪费的工作:

if next((True for x in other if x.exponent == term.exponent), False):

我认为您需要[x for x in y if x.attr == val],或者使用next与相同的表达式仅用于第一个这样的值。

在您的例子中,它可能看起来像这样:

def __add__(self, other):
    for term in self.terms:
        for other_term in (x for x in other.terms 
                             if x.exponent == term.exponent):
            term.coefficient += other_term.coefficient

然而,这不会很好地工作。首先,__add__不应该修改selfother,而是创建一个新的多项式。此外,这将忽略other中与self中的任何项具有不同指数的任何值。第三,性能非常糟糕,因为它对self中的每个项循环other中的项列表,使其具有二次复杂度。


相反,我建议使用字典,将项中的指数映射到它们的系数。事实上,你可能只需要使用collections.Counter;它已经以正确的方式实现了__add__。像这样:

class Poly:
    def __init__(self, counts):
        self.terms = collections.Counter(counts)
    def __add__(self, other):
        return Poly(self.terms + other.terms)
    def __str__(self):
        return " + ".join("%dx^%d" % (c, x) for x, c in self.terms.items())

的例子:

>>> Poly({2: 1, 1: 3, 0: 5}) + Poly({3: 1, 1: 2, 0: 3})
8x^0 + 5x^1 + 1x^2 + 1x^3