扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:开发者在线 2007年7月20日
关键字:
下面就让我们举一个真正派得上用场的例子。下面是一个相当标准的用于产生组合的函数,换句话说,一个序列可以以多种独特的方式被切割成小的序列:
def combination(seq, length):if not length: return [[]]else:l = []for i in xrange(len(seq)):for result in combination(seq[i+1:], length-1):l += [[seq[i]]+result]return l它的用法是:
>>> combination("ABCDE", 3)
[['A', 'B', 'C'], ['A', 'B', 'D'], ['A', 'B', 'E'], ['A', 'C', 'D'], ['A', 'C', 'E'], ['A', 'D', 'E'], ['B', 'C', 'D'], ['B', 'C', 'E'], ['B', 'D', 'E'], ['C', 'D', 'E']]
>>> combination("ABCDE", 2)
[['A', 'B'], ['A', 'C'], ['A', 'D'], ['A', 'E'], ['B', 'C'], ['B', 'D'], ['B', 'E'], ['C', 'D'], ['C', 'E'], ['D', 'E']]
>>> combination("ABCDE", 5)
[['A', 'B', 'C', 'D', 'E']]
现在让我们改用生成器来做同样的事情。你想要在某些点往最终结果列表里加入一个值并用yield语句替换掉它,因此这里的技巧是简单地替换掉每一个这样的点。
def xcombination(seq,length):
if not length: yield []
else:
for i in xrange(len(seq)):
for result in xcombination(seq[i+1:], length-1):
yield [seq[i]]+result
现在我们用另一种方式获得了同样结果,唯一的不同是它只会按照你的需要来工作:
>>> comb = xcombination("ABCDE", 3)
>>> comb.next()
['A', 'B', 'C']
>>> comb.next()
['A', 'B', 'D']
>>> list(comb)
[['A', 'B', 'E'], ['A', 'C', 'D'], ['A', 'C', 'E'], ['A', 'D', 'E'], ['B', 'C', 'D'], ['B', 'C', 'E'], ['B', 'D', 'E'], ['C', 'D', 'E']]
>>> comb2 = xcombination("ABCDE",2)
>>> for i in xrange(3):
... print comb2.next()
... ['A', 'B']
['A', 'C']
['A', 'D']
在最后一条命令里,尽管有10种不同的字母组合,但是只生成了3个,与标准的函数相比,这就节省了70%的计算时间。
生成器真正的有用之处在于,在大多数情况下它们可以用作替代列表推导的放下(Drop)。你需要做的是用圆括号替换掉列表推导前后的方括号。我们就举《列表推导》一文中的最后一个例子。我们不需要:
>>> guests = ['Chris', 'Brendan', 'Jimmy', 'Mel', 'Mike', 'Jess']
>>> [(seat1, seat2) for seat1 in guests for seat2 in guests if seat1 != seat2]
...
你可以改用:
>>> guests = ['Chris', 'Brendan', 'Jimmy', 'Mel', 'Mike', 'Jess']
>>> ((seat1, seat2) for seat1 in guests for seat2 in guests if seat1 != seat2)
然后你可以像使用其他任何生成器一样使用它:
>>> seating = ((seat1, seat2) for seat1 in guests for seat2 in guests if seat1 != seat2)
>>> for i in xrange(10):
... print seating.next()
...
('Chris', 'Brendan')
('Chris', 'Jimmy')
('Chris', 'Mel')
('Chris', 'Mike')
('Chris', 'Jess')
('Brendan', 'Chris')
('Brendan', 'Jimmy')
('Brendan', 'Mel')
('Brendan', 'Mike')
('Brendan', 'Jess')
到现在我们已经在使用生成器了,在创建列表上它比其他方法节约计算时间。这非常好,但是它大展拳脚的地方是在不可能计算整个列表的时候。我们就以Fibonacci序列为例,在这个序列里,每个数字都是前面两个数字的和。假设我们想要一个能够生成到指定数字的序列:
>>> def fib(n):...a, b = 0, 1...l = [a]...while b < n:...l += [b]...a, b = b, a+b...return l... >>> fib(20)[0, 1, 1, 2, 3, 5, 8, 13]如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者