将嵌套的Python循环转换为列表推导式

3

我已经开始解决一些欧拉计划中的问题,并用简单的暴力解决方案解决了第4个问题:

def mprods(a,b):
 c = range(a,b)
 f = []
 for d in c:
  for e in c:
   f.append(d*e)
 return f

max([z for z in mprods(100,1000) if str(z)==(''.join([str(z)[-i] for i in range(1,len(str(z))+1)]))])

在解决问题后,我试图尽可能地使它更加简洁,并想出了那个可怕的底线!
为了不半途而废,我正在尝试将函数压缩成列表推导式。到目前为止,我已经尝试了以下几种方法:
- [d*e for d,e in (range(a,b), range(a,b))] 显然完全走错了路。:-) - [d*e for x in [e for e in range(1,5)] for d in range(1,5)] 这给我带来了[4, 8, 12, 16, 4, 8, 12, 16, 4, 8, 12, 16, 4, 8, 12, 16],而我期望得到[1, 2, 3, 4, 2, 4, 6, 8, 3, 6, 9, 12, 4, 8, 12, 16]或类似的结果。
有没有Python专家可以帮忙? :)

1
使事物尽可能紧凑并不是一个明智的目标。 - Mike Graham
3个回答

7
c = range(a, b)
print [d * e for d in c for e in c]

谢谢!我不知道你可以这样做... :) - Lucas Jones
然后你可以将所有这些放在一起,得到[d*e for d in range(a,b) for e in range(a,b)]。此外,我建议使用xrange而不是range以获得更快的速度。 - Justin Peel
1
在迭代嵌套结构时,请注意顺序。需要先迭代外层:[x for y in N for x in y],否则当您尝试迭代内部结构(在本例中为 y)时,其名称将不存在。 - Ignacio Vazquez-Abrams
谢谢你的建议。今天又学到了几个Python小技巧! - Lucas Jones
@Justin:在Python 3.0中,没有xrange函数,而range返回一个像xrange一样的迭代器。为了模拟Python 2中的range,您可以调用list(range(x))。Lucas没有指定他使用的Python版本。 - Brian

3
from itertools import product

def palindrome(i):
  return str(i) == str(i)[::-1]

x = xrange(900,1000)

max(a*b for (a,b) in (product(x,x)) if palindrome(a*b))

  • xrange(900,1000) 类似于 range(900,1000),但不是返回一个列表,而是返回一个按需生成范围内数字的对象。对于循环而言,这比使用 range() 更快且更节省内存。

  • product(xrange(900,1000),xrange(900,1000)) 给出输入可迭代对象的笛卡尔积。它等价于嵌套的 for 循环。例如,product(A, B) 返回与下面相同的结果: ((x,y) for x in A for y in B)。最左边的迭代器在最外层的 for 循环中,因此输出元组的循环方式类似于里程表(每次迭代右侧的元素会发生变化)。

    product('ab', range(3)) --> ('a',0) ('a',1) ('a',2) ('b',0) ('b',1) ('b',2) product((0,1), (0,1), (0,1)) --> (0,0,0) (0,0,1) (0,1,0) (0,1,1) (1,0,0) ...

  • str(i)[::-1] 是列表切片的简写方式,用于反转列表。

  • 请注意,所有内容都被包裹在 生成器表达式 中,这是一种高性能、节省内存的列表推导和生成器的泛化形式。

  • 另请注意,由两个两位数相乘得到的最大回文数字是由 91 和 99 组成的,它们都属于 range(90,100)。如果推广到三位数,可以使用 range(900,1000)


这真的非常酷...又学到了一个新的Python特性 - 生成器表达式。很棒 :) - Lucas Jones
注意:这可以更加紧凑:max(a*b for (a,b) in product(xrange(900,1000),repeat=2) if str(a*b)==str(a*b)[::-1]) - Synthetica

2
我认为你会喜欢这个一行代码(为了易读性进行格式化):
max(z for z in (d*e
                for d in xrange(100, 1000)
                for e in xrange(100, 1000))
            if str(z) == str(z)[::-1])

稍微改变一下:
c = range(100, 1000)
max(z for z in (d*e for d in c for e in c) if str(z) == str(z)[::-1])

想知道在Lisp中会有多少个括号...


1
::-1?太酷了! :) Python 正在变成 NetHack - TDTTOE。谢谢。 - Lucas Jones

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接