Python:list comprehension生成连续的偶数子列表

时间:2018-04-23 13:22:21

标签: python python-3.x list list-comprehension

我尝试练习Python练习,但使用列表理解来解决问题而不是本书中显示的初学者样式循环。有一个例子,它要求将一个数字列表放入偶数列表中,但是它们必须在子列表中,这样如果数字跟随一个而不被奇数中断,它们应该放在一起进入子列表:

my_list = [2,3,5,7,8,9,10,12,14,15,17,25,31,32]
desired_output = [[2],[8],[10,12,14],[32]]

所以你可以在上面所需的输出中看到,10,12,14是彼此跟随的均匀而不被奇数打断,所以它们一起被放入子列表中。 8在它的两边都有一个奇数,因此在消除赔率后它会被单独放入一个子列表。

我可以使用下面的列表理解轻松地组合一个evens列表,但是我不知道如何将它放入像所需输出节目那样的子列表中。有人可以使用列表理解(或生成器,我不会介意,因为我现在正在尝试学习这两者)来建议这个想法。谢谢!

evens = [x for x in my_list if x%2==0]
print(evens)
[2, 8, 10, 12, 14, 32]

3 个答案:

答案 0 :(得分:3)

正如评论中所解释的那样,列表推导不应被视为"对于初学者而言#34; - 首先关注使用简单的for循环编写逻辑。

当您准备就绪时,您可以查看基于理解的方法。这是一个:

from itertools import groupby

my_list = [2,3,5,7,8,9,10,12,14,15,17,25,31,32]

condition = lambda x: all(i%2==0 for i in x)
grouper = (list(j) for _, j in groupby(my_list, key=lambda x: x%2))

res = filter(condition, grouper)

print(list(res))

# [[2], [8], [10, 12, 14], [32]]

在此解决方案中需要注意的要点是,在调用list(res)之前,不会计算任何内容。这是因为filter和生成器理解是懒惰的。

答案 1 :(得分:2)

您提到也想学习生成器,所以这里的版本也更具可读性,imho。

from itertools import groupby


def is_even(n):
    return n%2 == 0


def runs(lst):
    for even, run in groupby(lst, key=is_even):
        if even:
            yield list(run)


if __name__ == '__main__':
    lst = [2, 3, 5, 7, 8, 9, 10, 12, 14, 15, 17, 25, 31, 32]
    res = list(runs(lst))
    print(res)

顺便说一句,如果你绝对,积极地希望将它作为列表理解来实现,那么这个解决方案很自然地脱离了上述:

[list(run) for even, run in groupby(lst, key=is_even) if even]

答案 2 :(得分:1)

如果你不想使用itertools,还有另一种方法可以使用列表推导。

首先,取奇数元素的索引:

=IF(COUNTIF(U12, "A*") > 0, "Yes", "No")

并添加两个标记:[i for i,x in enumerate(my_list) if x%2==1] 之前和[-1]之后:

[len(my_list)]

你现在有类似的东西:

odd_indices = [-1]+[i for i,x in enumerate(my_list) if x%2==1]+[len(my_list)]
# [-1, 1, 2, 3, 5, 9, 10, 11, 12, 14]

你可以看到你的序列。现在,取这些指数之间的元素。要做到这一点,请将 [2,3,5,7,8,9,10,12,14,15,17,25,31,32] ^---^-^-^---^-----------^--^--^--^----^ 与自身压缩以获得区间作为元组:

odd_indices

您只需要过滤非空列表:

zip(odd_indices, odd_indices[1:])
# [(-1, 1), (1, 2), (2, 3), (3, 5), (5, 9), (9, 10), (10, 11), (11, 12), (12, 14)]    

even_groups = [my_list[a+1:b] for a,b in zip(odd_indices, odd_indices[1:])]
# [[2], [], [], [8], [10, 12, 14], [], [], [], [32]]

您可以将这两个步骤合并为一个理解列表,但这有点不可读:

even_groups = [my_list[a+1:b] for a,b in zip(odd_indices, odd_indices[1:]) if a+1<b]
# [[2], [8], [10, 12, 14], [32]]

正如@jpp所指出的那样,在你感到舒服之前,首选基本循环。也许永远避免那些嵌套列表理解......