
首先使用 filter() 并找到所有短边是小于 10 的毕达哥拉斯三元组。并不到对组合进行两次测试:
# pythagorean.triple.pyfrom math import sqrt# this will generate all possible pairsmx = 10triples = [(a, b, sqrt(a**2 + b**2)) for a in range(1, mx) for b in range(a, mx)]# this will filter out all non-Pythagorean triplestriples = list( filter(lambda triple: triple[2].is_integer(), triples))print(triples) # prints: [(3, 4, 5.0), (6, 8, 10.0)]毕达哥拉斯三元组是满足方程 a2 + b2 = c2 的整数的三元组 (a, b, c) 。
在在前面的代码中,生成了一个包含三元组、三元组的列表。每个元组包含两个整数和毕达哥拉斯三角形的斜边,例如,当 a 为 3 且 b 为 4 时,元组将为 (3, 4, 5.0),当 a 为 5 且 b 为 7 时,元组将为 (5, 7, 8.602325267042627)。
在生成所有三元组之后,需要过滤掉所有斜边不是整数的三元组。为此,根据 float_number 进行筛选。is_integer() 为 True。这意味着,在刚刚向展示的两个示例元组中,斜边为 5.0 的元组将被保留,而斜边为 8.602325267042627 的元组将被丢弃。
使用 map() 来解决这个问题
# pythagorean.triple.int.pyfrom math import sqrtmx = 10triples = [(a, b, sqrt(a**2 + b**2)) for a in range(1, mx) for b in range(a, mx)]triples = filter(lambda triple: triple[2].is_integer(), triples)# this will make the third number in the tuples integertriples = list( map(lambda triple: triple[:2] + (int(triple[2]), ), triples))print(triples) # prints: [(3, 4, 5), (6, 8, 10)将每个元素分成三元组并对其进行切片,只取其中的前两个元素。然后,将切片 与一个 one-tuples 连接起来,其中有 float number 的整数版本。看起来工作量很大,对吧?确实如此。让我们看看如何使用列表推导式来完成所有这些操作:
# pythagorean.triple.comprehension.pyfrom math import sqrt# this step is the same as beforemx = 10triples = [(a, b, sqrt(a**2 + b**2)) for a in range(1, mx) for b in range(a, mx)]# here we combine filter and map in one CLEAN list comprehensiontriples = [(a, b, int(c)) for a, b, c in triples if c.is_integer()]print(triples) # prints: [(3, 4, 5), (6, 8, 10)]这个好多了,可读且更短。不过,它并不像它本来应该的那样简洁。仍然在浪费内存,构建一个包含大量三元组的列表,现在不使用这些三元组。可以通过将两个推导式合二为一来解决这个问题:
# pythagorean.triple.walrus.pyfrom math import sqrt# this step is the same as beforemx = 10# We can combine generating and filtering in one comprehensiontriples = [(a, b, int(c)) for a in range(1, mx) for b in range(a, mx) if (c := sqrt(a**2 + b**2)).is_integer()]print(triples) # prints: [(3, 4, 5), (6, 8, 10)]这个通过生成三元组并在同一个列表推导式中过滤它们,避免了将任何未通过测试的三元组保留在内存中。请注意,使用了赋值表达式,以避免需要计算 sqrt(a**2 + b**2) 的值两次。