我有这样的代码:
good = [x for x in mylist if x in goodvals]
bad = [x for x in mylist if x not in goodvals]
目标是根据mylist的内容是否满足条件,将它们拆分为另外两个列表。
我怎样才能做得更优雅呢?我能避免在mylist上做两个单独的迭代吗?我可以通过这样做来提高性能吗?
我有这样的代码:
good = [x for x in mylist if x in goodvals]
bad = [x for x in mylist if x not in goodvals]
目标是根据mylist的内容是否满足条件,将它们拆分为另外两个列表。
我怎样才能做得更优雅呢?我能避免在mylist上做两个单独的迭代吗?我可以通过这样做来提高性能吗?
当前回答
def partition(pred, iterable):
'Use a predicate to partition entries into false entries and true entries'
# partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9
t1, t2 = tee(iterable)
return filterfalse(pred, t1), filter(pred, t2)
检查这个
其他回答
如果列表由组和间歇分隔符组成,您可以使用:
def split(items, p):
groups = [[]]
for i in items:
if p(i):
groups.append([])
groups[-1].append(i)
return groups
用法:
split(range(1,11), lambda x: x % 3 == 0)
# gives [[1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]
images = [f for f in files if f[2].lower() in IMAGE_TYPES]
anims = [f for f in files if f not in images]
当条件较长时很好,例如在您的示例中。读者不需要弄清楚否定条件以及它是否适用于所有其他情况。
good.append(x) if x in goodvals else bad.append(x)
来自@dansalmo的这个优雅简洁的回答被埋没在评论中,所以我只是把它作为一个答案转发到这里,这样它就能得到应有的重视,尤其是对新读者来说。
完整的例子:
good, bad = [], []
for x in my_list:
good.append(x) if x in goodvals else bad.append(x)
我基本上喜欢安德斯的方法,因为它非常普遍。下面的版本将分类器放在前面(以匹配过滤器语法),并使用defaultdict(假定已导入)。
def categorize(func, seq):
"""Return mapping from categories to lists
of categorized items.
"""
d = defaultdict(list)
for item in seq:
d[func(item)].append(item)
return d
还有另一个答案,简短但“邪恶”(用于理解列表的副作用)。
digits = list(range(10))
odd = [x.pop(i) for i, x in enumerate(digits) if x % 2]
>>> odd
[1, 3, 5, 7, 9]
>>> digits
[0, 2, 4, 6, 8]