我有一个类,它将多项式表示为项的集合,其中每个项有一个系数和一个指数。我正在研究该类的__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__
不应该修改self
和other
,而是创建一个新的多项式。此外,这将忽略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