mapfilter是Python中的两种高效函数,用于处理可迭代对象。然而,如果你同时使用mapfilter,代码会显得很乱。

list1 = [1, 2, 3, 4, 5, 6, 7]

str = list(map(lambda x: x * 2, filter(lambda x: x % 2 == 0, list1)))

print(str)  # [4, 8, 12]

如果你能像下面这样使用管道|在一个迭代器上应用多个方法,那不是很好吗?

from pipe import select, where

str2 = list(list1 | where(lambda x: x % 2 == 0) | select(lambda x: x * 2))

print(str2)  # [4, 8, 12]

什么是Pipe?

Pipe是一个Python库,使你能够在Python中使用管道。一个管道(|)将一个方法的结果传递给另一个方法。

Pipe很受欢迎,因为它使我们的代码在对Python迭代器应用多种方法时看起来更干净。由于Pipe中的函数屈指可数,所以学习Pipe也非常容易。

首先需要安装Pipe:

pip install pipe

Where

迭代器中的过滤元素--where

SQL类似,Pipe的where方法也可以用来过滤迭代表中的元素。

from pipe import where

str3 = list(list1 | where(lambda x: x % 2 == 0))

print(str3)  # [2, 4, 6]

Select

将一个函数应用到一个迭代器上—select

select方法与map方法类似。select将一个方法应用于迭代器的每个元素。

在下面的代码中,我使用select将列表中的每个元素乘以2。

from pipe import select

str4 = list(list1 | select(lambda x: x * 2))

print(str4)  # [2, 4, 6, 8, 10, 12, 14]

现在,你可能想知道:如果whereselect的功能与mapfilter相同,我们为什么还需要这些方法?

因为可以使用管道在另一个方法之后插入一个方法。因此,使用管道可以去除嵌套的小括号,使代码更容易阅读。

from pipe import select, where

s2 = list(list1
          | where(lambda x: x % 2 == 0)
          | select(lambda x: x * 2)
          )

print(s2)  # [4, 8, 12]

Chain

迭代序列的链路--chain

处理嵌套的迭代器可能是一件很痛苦的事情。而我们可以使用chain来链接一连串的迭代变量。

from pipe import chain

arr = [[1, 2, [3, ]], [4, 5]]

str5 = list(arr | chain)

print(str5) # [1, 2, [3], 4, 5]

尽管应用链式后迭代器的嵌套程度降低了,我们仍然有一个嵌套的列表。要处理一个深度嵌套的列表,可以使用 traverse 来代替。

Traverse

递归展开迭代器--traverse

traverse方法可以用来递归地展开迭代器。因此,你可以用这个方法把一个深度嵌套的列表变成一个一维列表。

from pipe import traverse

arr = [[1, 2, [3, ]], [4, 5]]
str6 = list(arr | traverse)

print(str6)  # [1, 2, 3, 4, 5]

把这个方法和select方法整合起来,以获得一个字典的值,并把列表扁平化。

from pipe import traverse, select

gr = [
    {'name': 'Apple', 'Price': [2, 5]},
    {'name': 'Orange', 'Price': 3},
    {'name': 'Grape', 'Price': 6},
]

str7 = list(gr
            | select(lambda g: g['Price'])
            | traverse
            )

print(str7)  # [2, 5, 3, 6]

列表中的元素分组

有时,使用某个函数对列表中的元素进行分组可能是有用的。这可以用groupby方法轻松实现。

为了看看这个方法是如何工作的,把一个数字列表变成一个字典,根据数字是偶数还是奇数来分组。

from pipe import groupby, select

str8 = list(
    (1, 2, 3, 4, 5, 6, 7, 8, 9)
    | groupby(lambda x: 'Even' if x % 2 == 0 else 'Odd')
    | select(lambda x: {x[0]: list(x[1])})
)

print(str8)  # [{'Even': [2, 4, 6, 8]}, {'Odd': [1, 3, 5, 7, 9]}]

在上面的代码中,我们使用groupby将数字分组为Even组和Odd组。应用这个方法后的输出看起来像下面这样:

[('Even', <itertools._grouper at 0x7fbea8030550>),
 ('Odd', <itertools._grouper at 0x7fbea80309a0>)]

接下来,我们使用select将一个元组变成一个字典的列表,其键是元组中的第一个元素,值是元组中的第二个元素。

[{'Even': [2, 4, 6, 8]},
 {'Odd': [1, 3, 5, 7, 9]}]

为了只获得大于2的值,我们可以在选择方法中加入where方法:

from pipe import groupby, select, where

str9 = list(
    (1, 2, 3, 4, 5, 6, 7, 8, 9)
    | groupby(lambda x: 'Even' if x % 2 == 0 else 'Odd')
    | select(lambda x: {x[0]: list(x[1] | where(lambda x: x > 2))})
)

print(str9)  # [{'Even': [4, 6, 8]}, {'Odd': [3, 5, 7, 9]}]

请注意,输出中不再有21

Dedup

使用一个键来重复取值--dedup

dedup方法删除列表中的重复部分。

from pipe import dedup

L2 = [2, 1, 4, 5, 7, 5, 6, 5, 7, 8, 5, 4, 1, 2, 5, 3, 6, 5, 4, 5, 8, 5, 4, 8, 6, 2, 4, 7, 9]
L3 = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 4, 4, 2, 4, 1]

str10 = list(L2 | dedup)
str11 = list(L3 | dedup)

print(str10)  # [2, 1, 4, 5, 7, 6, 8, 3, 9]
print(str11)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

这听起来可能没什么意思,因为set方法可以做同样的事情。然而,这种方法更加灵活,因为它使你能够使用一个键获得独特的元素。

例如,你可以用这个方法来获得一个小于5唯一元素和另一个大于等于5唯一元素。

str11 = list(L3 | dedup(lambda key: key < 5))

print(str11)  # [1, 5]

现在,把这个方法与 selectwhere 结合起来,得到一个有重复键和 None 值的字典的值。

from pipe import dedup, select, where

data = [
    {'name': 'Apple', 'Count': 2},
    {'name': 'Orange', 'Count': 4},
    {'name': 'Grape', 'Count': None},
    {'name': 'Orange', 'Count': 7},
]

str12 = list(
    data
    | dedup(key=lambda g: g['name'])
    | select(lambda g: g['Count'])
    | where(lambda count: isinstance(count, int))
)

print(str12)  # [2, 4]

在上面的代码中,我们:

  • 移除同名的元素;

  • 获得count的值;

  • 只选择整数的值。

在几行代码中,我们可以将多个方法应用于一个迭代器,同时仍然保持代码的简洁。

总结

本文中,None和大家一起学会了如何使用管道来保持你的代码的简洁和简短。

我希望这篇文章能给你带来知识,把对迭代器的复杂操作变成一行简单的代码

参考资料

[1] Pipe: https://github.com/JulienPalard/Pipe
声明:如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。None#python87.com