如何用函数式方法在Python中实现字典列表转列表字典与文件分组
我太懂这种从Scala切换到Python后,想念函数式数据处理丝滑感的心情了!尤其是group by这类操作在Scala里简直顺手到不行,刚转Python时确实会有点摸不着头脑——不过放心,不用pandas也完全能搞定,而且用函数式风格实现的话,体验能无限接近你熟悉的Scala感觉。
一、用函数式方法分组Path列表(训练/验证集划分)
假设你已经有了which_set函数,能接收pathlib.Path对象并返回"train"或"val"这类集合名称,这里有两种纯函数式的实现方式:
方法1:字典推导式(直观简洁)
这种方式最接近Scala中groupBy的语义,直接遍历所有Path对象,按分组键筛选:
from pathlib import Path # 示例which_set函数,你可以替换成自己的逻辑 def which_set(file_path: Path) -> str: return "train" if "train" in file_path.parent.name else "val" # 你的Path列表 all_paths = [ Path("data/train/img1.jpg"), Path("data/val/img2.jpg"), Path("data/train/img3.jpg"), Path("data/val/img4.jpg") ] # 分组操作 grouped_sets = { set_name: [path for path in all_paths if which_set(path) == set_name] for set_name in {"train", "val"} } # 结果:{"train": [Path(...), Path(...)], "val": [Path(...), Path(...)]}
这个方法的优势是清晰直观,完全不需要额外依赖,而且直接操作Path对象,不用转成字符串。
方法2:用functools.reduce(更灵活的聚合)
如果你的分组键是动态生成的(比如不止train/val两种),用reduce来逐步聚合会更灵活:
from functools import reduce from pathlib import Path def which_set(file_path: Path) -> str: return "train" if "train" in file_path.parent.name else "val" all_paths = [Path("data/train/img1.jpg"), Path("data/val/img2.jpg"), ...] # 用reduce逐个将Path添加到对应分组 grouped_sets = reduce( lambda acc, path: acc[which_set(path)].append(path) or acc, all_paths, # 初始化空字典,如果分组键动态,也可以改成{},然后用setdefault {"train": [], "val": []} )
这里利用了append返回None的特性,用or acc确保每次迭代都返回更新后的字典,和Scala中折叠(fold)操作的逻辑一致。
二、从字典列表创建列表字典的函数式实现
比如把[{"a":1, "b":2}, {"a":3, "b":4}]转换成{"a":[1,3], "b":[2,4]},同样有两种函数式思路:
方法1:字典推导式(适用于键统一的场景)
如果所有字典的键都相同,直接推导式就能搞定:
dict_list = [{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6}] list_dict = { key: [d[key] for d in dict_list] for key in dict_list[0].keys() }
方法2:用functools.reduce(处理键不统一的情况)
如果字典列表里的键可能不一致,reduce能动态收集所有存在的键:
from functools import reduce dict_list = [{"a":1, "b":2}, {"a":3}, {"b":4, "c":5}] def merge_to_list_dict(acc, current_dict): for key, value in current_dict.items(): # 键不存在就初始化空列表,再追加值 acc.setdefault(key, []).append(value) return acc list_dict = reduce(merge_to_list_dict, dict_list, {}) # 结果:{"a": [1,3], "b": [2,4], "c": [5]}
这个方法的灵活性更高,不管输入的字典有没有相同的键,都能正确聚合。
内容的提问来源于stack exchange,提问作者Piotr Czapla
相关产品推荐
相关产品推荐

