给定regex.findall()
的组字典列表:
[{'short_name': 'f1', 'long_name': 'ae123'}, {'short_name': 'f2', 'long_name': 'ae123'}, {'short_name': 'f3', 'long_name': 'x89zy'}, {'short_name': 'f4', 'long_name': 'bc00'}, {'short_name': 'f5', 'long_name': 'bc00'}]
我想通过'short_name'键对这些字典进行分组,但是我很好奇如何在Python中使用函数式编程技术来做到这一点。
目前为止我的代码是:
def parse_fonts(style):
sheet = parse_stylesheet(style, skip_comments=True, skip_whitespace=True)
values_by_long_name = {}
fonts = map(
lambda x: FONT_REGEX.search(x.serialize()).groupdict(),
sheet[1:]
)
values_by_long_name = {}
for font in fonts:
values_by_long_name.setdefault(
font['long_name'], []).append(font['short_name'])
return values_by_long_name
上面的代码返回如下内容:
[{'long_name': 'ae123', 'short_name': ['f1', 'f2']}, {'long_name': 'x89zy', 'short_name': ['f3']}, {'long_name': 'bc00', 'short_name': ['f4', 'f5']}]
如果不使用for循环/列表推导,如果可能的话,在一个函数调用链中,如a(b(c(d(x))))
,我如何实现相同的目标?
你的实现可能是我在Python中使用的,它本身并不是非函数的——从某种意义上说,纯函数实现仍然将遵循相同的逻辑:
- 折叠输入列表,使用字典/映射累加器
- 对于每个(键,值)对,检查键是否存在于映射 中。
- 更新映射(即返回一个新映射),如果键存在,则附加值,否则为键 插入一个新的单例[value]
我猜你可以在Pyton中使用itertools.groupby
,但它不是很令人满意,因为你仍然需要一个助手来获得相同的输出形状:
import itertools
lst =[{'short_name': 'f1', 'long_name': 'ae123'},
{'short_name': 'f2', 'long_name': 'ae123'},
{'short_name': 'f3', 'long_name': 'x89zy'},
{'short_name': 'f4', 'long_name': 'bc00'},
{'short_name': 'f5', 'long_name': 'bc00'}]
def regroup(groups):
"""Regroup groupby result."""
return [{'long_name': key, 'short_name': [g['short_name'] for g in group]}
for key, group in groups]
g = regroup(itertools.groupby(lst, lambda x: x['long_name']))
print(g)
…outpus:
[{'long_name': 'ae123', 'short_name': ['f1', 'f2']}, {'long_name': 'x89zy', 'short_name': ['f3']}, {'long_name': 'bc00', 'short_name': ['f4', 'f5']}]
在语法层面上,使用函数式语言确实可以更简洁,就像Haskell中的这个例子:
import qualified Data.Map as M
pairs = [("f1", "ae123"), ("f2", "ae123"), ("f3", "x89zy"), ("f4", "bc00"), ("f5", "bc00")]
group :: Ord b => [(a, b)] -> M.Map b [a]
group = M.fromListWith (++) . map swap
where
swap(a, b) = (b, [a])
…交互运行时会产生:
*Main M> group pairs
fromList [("ae123",["f2","f1"]),("bc00",["f5","f4"]),("x89zy",["f3"])]
如果您对Python中的函数式编程感兴趣,我将重点讨论使用mypy
对类型进行推理并限制副作用的使用,因为语法通常会更冗长。(请注意,列表推导式是非常实用的——相当于map
函数,它对列表中的每个值应用一些函数,而不改变其形状。)