有没有办法捕捉列表理解中的失误?

Jon*_*sco 3 python

基于简单的列表理解:

yay = [ i for i in a if a[i] ]
nay = [ i for i in a if not a[i] ]
Run Code Online (Sandbox Code Playgroud)

我想知道是否有办法同时分配yaynay值(即有条件的命中和未命中)?

看起来像这样的东西

( yay , nay ) = ...
Run Code Online (Sandbox Code Playgroud)

我对可读性和速度感到好奇(看到两个列表推导比单个for循环附加到列表中的速度快5%,我感到有些惊讶)


更新:

最初的例子是在dict中获取"true"和"false"有价值键的列表...

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]
Run Code Online (Sandbox Code Playgroud)

Dun*_*can 7

这里通常的解决方案是不要全神贯注于使用列表理解的想法.只需使用一个for循环:

yay, nay = [], []
for i in a:
    if somecondition(i):
        yay.append(i)
    else:
        nay.append(i)
Run Code Online (Sandbox Code Playgroud)

如果你发现自己做了很多,那么只需将代码移到一个函数中:

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])
Run Code Online (Sandbox Code Playgroud)

评论表明这比列表理解慢.将条件作为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
Run Code Online (Sandbox Code Playgroud)

我不知道这是否会带来很大的不同,但定时它可能会很有趣.

在评论中@martineau建议使用生成器并使用它any().我会在这里包含它,但我会any用itertools配方代替使用迭代器:

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)
Run Code Online (Sandbox Code Playgroud)

然后你可以写:

yay, nay = [], []
consume((yay if a[i] else nay).append(i) for i in a)
Run Code Online (Sandbox Code Playgroud)