基于简单的列表理解:
yay = [ i for i in a if a[i] ]
nay = [ i for i in a if not a[i] ]
我想知道是否有办法同时分配yay
和nay
值(即有条件的命中和未命中)?
看起来像这样的东西
( yay , nay ) = ...
我对可读性和速度感到好奇(我看到两个列表推导比单个for循环附加到列表中的速度快5%有点惊讶)
更新
最初的例子是在字典中获取“真实”和“虚假”有价值键的列表......
a = {i: i >= 50 for i in range(100)}
yay = [k for k, v in a.items() if v]
nay = [k for k, v in a.items() if not v]
答案 0 :(得分:7)
这里通常的解决方案不是让所有人都想要使用列表理解。只需使用for
循环:
yay, nay = [], []
for i in a:
if somecondition(i):
yay.append(i)
else:
nay.append(i)
如果你发现自己做了很多,那么只需将代码移到一个函数中:
def yesno(seq, cond):
yay, nay = [], []
for i in seq:
if cond(i):
yay.append(i)
else:
nay.append(i)
return yay, nay
yay, nay = yesno(a, lambda x: a[x])
评论表明这比列表理解慢。将条件作为lambda传递将不可避免地受到重创,我不认为你可以做很多事情,但是一些性能损失可能来自查找append
方法并且可以改进:
def yesno(seq, cond):
yay, nay = [], []
yes, no = yay.append, nay.append
for i in seq:
if cond(i):
yes(i)
else:
no(i)
return yay, nay
我不知道这是否会带来很大的不同,但定时它可能会很有趣。
在评论中@martineau建议使用生成器并将其与any()
一起使用。我将在这里包含,但我会用itertools配方替换any
以使用迭代器:
def consume(iterator, n):
"Advance the iterator n-steps ahead. If n is none, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)
然后你可以写:
yay, nay = [], []
consume((yay if a[i] else nay).append(i) for i in a)
答案 1 :(得分:4)
我仍然会说,你的做法更具可读性,应该是建议的方法,但无论如何,如果你正在寻找替代方案,你可以期待来自itertools的解决方案
>>> from itertools import compress, imap
>>> from operator import not_
>>> yay, nay = compress(a,a.values()), compress(a, imap(not_,a.values()))
答案 2 :(得分:0)
这可以通过以下方式完成:
yay, nay = zip(*[(k, None) if v else (None, k) for k, v in a.items()])
yay, nay = filter(None, yay), filter(None, nay)
至于它是否会更快......也许是为了巨大的名单。否则,它可能不重要。
当然,如果None
是您的列表中的值,则需要将其换成另一个哨兵并使用filter()
进行身份检查。
答案 3 :(得分:0)
你可能能够使用词典理解,但我有理由相信你不能*使用列表理解来做你所要求的。假设数据是或可以排序**我可能会使用itertools.groupby
。
results = itertools.groupby(sorted_a, bool)
*资格:好的,Lattyware的答案显示你可以,但它也为iterable的每个成员生成一个None
值的元组。 IMO认为这很浪费。虽然我承认我甚至没有考虑到这一点,但我并不感到羞耻,因为我没有。
**排序:需要按照分组的相同键进行排序。
答案 4 :(得分:0)
它不漂亮,但你可以在这些方面做点什么:
nay = []
yay = [foo for foo in foos if condition or nay.append(foo)]
这利用了or
运算符上的短路。
答案 5 :(得分:0)
修改
哦,我写了一个与Duncan的解决方案完全相同的解决方案。所以我删除了我写的内容,我让我认为是最好的解决方案,混合一个Duncan的解决方案和martineau的提议(使用 any()在我看来比使用更好 list()或列表理解是我写过的;非常好的想法 any(),这比导入 consume()的复杂性更好 IMO)
def disting(L):
dust,right = [],[]
dustapp = dust.append
rightapp = right.append
any(rightapp(x) if x else dustapp(x) for x in L)
return right,dust
for seq in ((10,None,'a',0,None,45,'qada',False,True,0,456),
[False,0,None,104,True,str,'',88,'AA',__name__]):
yay,nay = disting(seq)
print 'seq == %r\nyay == %r\nnay == %r' % (seq,yay,nay)
print '---------------------------------------'
结果
seq == (10, None, 'a', 0, None, 45, 'qada', False, True, 0, 456)
yay == [10, 'a', 45, 'qada', True, 456]
nay == [None, 0, None, False, 0]
---------------------------------------
seq == [False, 0, None, 104, True, <type 'str'>, '', 88, 'AA', '__main__']
yay == [104, True, <type 'str'>, 88, 'AA', '__main__']
nay == [False, 0, None, '']
---------------------------------------
顺便说一下,使用 any()有效,因为rightapp(x)
和dustapp(x)
会返回无。如果返回True或等效于True, any()内的迭代将停止!