基本上我想做的是获取两个对象列表并根据一些测试将它们分成两个列表,具体取决于结果是True
还是False
。对filter()
所做的事情进行排序,除了确定它是否进入或确定它确定要转到哪个列表/迭代器之外。我使用itertools.groupby()
:
import random
from itertools import groupby
class FooObject(object):
def __init__(self):
self.key = random.choice((True, False))
def __repr__(self):
return '<Foo: %s>' % self.key
foos = [FooObject() for _ in range(10)]
left, right = [], []
groups = groupby(sorted(foos, key=lambda o: o.key), lambda o: o.key)
for k, group in groups:
if k:
right = list(group)
else:
left = list(group)
print left
print right
这可以完成工作,但只是想知道是否有更清晰/更简单的方法。我意识到我可以使用filter()
(或等效的列表理解)并在两遍中完成它,但那有什么乐趣?
答案 0 :(得分:1)
这是一个仅消耗源一次的函数,它返回一个类似字典的对象,每个成员都是一个生成器,它尽可能从源中生成值:
def partition(it, fun):
class x(object):
def __init__(self):
self.buf = {}
def flush(self, val):
for p in self.buf.get(val, []):
yield p
self.buf.pop(val, None)
def __getitem__(self, val):
for p in self.flush(val): yield p
while True:
try:
p = next(it)
except StopIteration:
break
v = fun(p)
if v == val:
yield p
else:
self.buf.setdefault(v, []).append(p)
for p in self.flush(val): yield p
return x()
使用示例:
def primes(): # note that this is an endless generator
yield 2
p, n = [], 3
while True:
if all(n % x for x in p):
p.append(n)
yield n
n += 2
p = partition(primes(), lambda x: x % 3)
# each member of p is endless as well
for x in p[1]:
print x
if x > 200: break
for x in p[2]:
print x
if x > 200: break
答案 1 :(得分:1)
如果您只有2个桶,则可以使用三元组:
d={'left':[],'right':[]}
for e in (random.random() for i in xrange(50)):
d['left' if e<0.5 else 'right'].append(e)
使用超过2个存储桶,使用一个返回已定义的键的函数或使用带有列表的默认字典:
def f(i):
return int(i*10)
DoL=defaultdict(list)
for e in (random.random() for i in xrange(50)):
DoL[f(e)].append(e)