如何将键为电影、值为演员列表的字典反转为键为演员、值为电影列表的字典

本文详解如何将原始字典(电影→[演员列表])高效反转为演员索引字典(演员→[电影列表]),并处理真实数据中常见的换行断裂问题,最终实现按演员名快速查询参演影片的功能。

在*数据处理中,常需从“电影→演员”映射切换为“演员→电影”索引,以支持按人查片等交互需求。原始代码构建的是 movie_dictionary = {"La La Land": ["Ryan Gosling", "Emma Stone"], ...},但用户需要输入演员名(如 "Harrison Ford")后,直接获取其所有参演影片。这本质上是字典的键值反转,但由于值为列表且存在一对多关系,不能简单使用 {v: k for k, v in d.items()} —— 必须将每个演员作为新键,将其出现的所有电影逐个追加到对应列表中。

✅ 正确的反转逻辑:遍历 + setdefault()

核心思路是:对每一行数据,先分离出电影名和演员列表;再对每位演员(需 .strip() 清理空格),使用 dict.setdefault(key, []) 确保该演员键存在且值为列表,然后 .append(movie):

# 示例:模拟读取文件后的数据行
rows = [
    "La La Land, Ryan Gosling, Emma Stone",
    "Blade Runner 2049, Harrison Ford, Ryan Gosling, Ana de Armas",
    # ... 其他行(已确保格式完整)
]

appears_in = {}  # 反转后的字典:演员 → [电影列表]
for row in rows:
    parts = row.split(',')
    movie = parts[0].strip()
    actors = [a.strip() for a in parts[1:]]  # 清理每位演员首尾空格
    for actor in actors:
        appears_in.setdefault(actor, []).append(movie)

✅ setdefault() 是关键:若 actor 键不存在,则初始化为空列表 [] 并返回该列表;若已存在,则直接返回原列表。后续 .append(movie) 安全追加,避免 KeyError 或重复初始化。

⚠️ 真实数据陷阱:换行导致的字段断裂

观察原始 movies and actors.txt,部分行末尾有换行符中断(如 "My Best Friend's Wedding, Julia Roberts, dermont Multroney, \nCameron Diaz"),导致 split(',') 后出现孤立的 " Cameron Diaz" 作为独立行,破坏结构。

修复策略:合并被截断的行
遍历每行,若某行 split(',') 后仅得 1 段(即无逗号),说明它是上一行的延续,应拼接到前一行末尾:

def fix_broken_lines(raw_lines):
    fixed = []
    buffer = ""
    for line in raw_lines:
        line = line.strip()
        if not line:
            continue
        parts = line.split(',')
        if len(parts) == 1 and buffer:  # 孤立片段,追加到缓冲区
            buffer += ", " + line
        else:
            if buffer:
                fixed.append(buffer)
            buffer = line
    if buffer:
        fixed.append(buffer)
    return fixed

# 使用示例
with open("movie and actors.txt", "r") as f:
    raw_rows = f.readlines()
fixed_rows = fix_broken_lines(raw_rows)

? 完整可运行程序(含错误处理)

def build_actor_movie_index(filename):
    """从文件构建演员→电影列表字典,自动修复换行断裂"""
    with open(filename, "r", encoding="utf-8") as f:
        lines = f.readlines()

    # 步骤1:修复断裂行
    rows = []
    buffer = ""
    for line in lines:
        stripped = line.strip()
        if not stripped:
            continue
        if "," not in stripped and buffer:  # 无逗号且有前置内容 → 属于上一行
            buffer += " " + stripped
        else:
            if buffer:
                rows.append(buffer)
            buffer = stripped
    if buffer:
        rows.append(buffer)

    # 步骤2:构建反转字典
    appears_in = {}
    for row in rows:
        parts = row.split(',')
        if len(parts) < 2:
            continue  # 跳过无效行
        movie = parts[0].strip()
        actors = [a.strip() for a in parts[1:] if a.strip()]
        for actor in actors:
            appears_in.setdefault(actor, []).append(movie)

    return appears_in

# 主程序
if __name__ == "__main__":
    try:
        index = build_actor_movie_index("movie and actors.txt")
        name = input("Enter an actor/actress name: ").strip()

        if name in index:
            movies = index[name]
            print(f"The movies that '{name}' starred in are: {', '.join(movies)}")
        else:
            print(f"No movies found for '{name}'. Check spelling or try another name.")

    except FileNotFoundError:
        print("Error: File 'movie and actors.txt' not found.")
    except Exception as e:
        print(f"An error occurred: {e}")

? 关键总结

  • 不要用 dict(zip(values, keys)):因原值是列表,会丢失多对一关系;
  • 优先用 setdefault():比手动 if key not in d: d[key] = [] 更简洁安全;
  • 务必清洗数据:.strip() 处理空格,预处理修复换行断裂;
  • 增强健壮性:加入 try/except 和空行/无效行过滤;
  • 用户体验优化:提示拼写检查,避免 KeyError 导致程序崩溃。

通过以上方法,你不仅能正确反转字典结构,还能应对真实数据中的典型噪声,构建出可靠、可维护的*索引系统。