讲师中心 微信公众号
AI工具推荐 视频效率加速

Python中高效统计字典嵌套列表中元素出现次数的教程

星静吖_2738

星静吖_2738

发布时间:2025-12-03 12:34:02

|

786人浏览过

|

来源于php中文网

原创

Python中高效统计字典嵌套列表中元素出现次数的教程

本教程旨在解决如何高效统计一个字典中,其值(一个列表)所包含的元素在另一个主列表中出现的总次数,并生成一个新的字典。我们将从分析传统嵌套循环方案的低效率(o(n^3)时间复杂度)入手,详细阐述一种通过预处理主列表来优化性能(降至o(n)时间复杂度)的纯python解决方案,并提供完整的代码示例及性能分析。

问题描述

在Python编程中,我们经常会遇到需要处理复杂数据结构的情况。假设我们有一个字典my_dict,其键是字符串,值是一个包含字符串的列表。同时,我们还有一个主列表my_list。我们的目标是创建一个新的字典new_dict,其中键与my_dict的键相同,而值则是该键对应的列表中所有元素在my_list中出现的总次数。

例如,给定以下数据:

my_dict = {'A': ['A', 'B'], 'B': ['C', 'D'], 'C': ['E', 'F']}
my_list = ['A', 'D', 'A', 'C', 'F', 'F']

我们期望得到的new_dict输出为:

{'A': 2, 'B': 2, 'C': 2}

解释:

立即学习“Python免费学习笔记(深入)”;

  • 对于键 'A',其值为 ['A', 'B']。在 my_list 中,'A' 出现了2次,'B' 出现了0次。因此,'A' 的总计数为 2。
  • 对于键 'B',其值为 ['C', 'D']。在 my_list 中,'C' 出现了1次,'D' 出现了1次。因此,'B' 的总计数为 1 + 1 = 2。
  • 对于键 'C',其值为 ['E', 'F']。在 my_list 中,'E' 出现了0次,'F' 出现了2次。因此,'C' 的总计数为 2。

低效的解决方案及其性能瓶颈

初学者可能会倾向于使用多层嵌套循环来解决这个问题,例如:

# 假设的低效实现思路,仅作说明,不推荐
new_dict = {}
for key, values in my_dict.items(): # 外层循环1:遍历my_dict的键值对
    count_for_key = 0
    for list_val in values: # 内层循环2:遍历my_dict值中的列表元素
        for element in my_list: # 最内层循环3:遍历my_list
            if element == list_val:
                count_for_key += 1
    new_dict[key] = count_for_key

或者,如果使用 in 操作符来检查元素是否存在:

# 另一种低效实现思路,使用 `in` 操作符
new_dict = {}
for key, values in my_dict.items(): # 遍历my_dict的键值对
    new_dict[key] = 0
    for val_in_dict_list in values: # 遍历my_dict值中的列表元素
        # 此处隐藏了一个遍历:list_val in my_list
        # Python的 `in` 运算符对于列表的性能是 O(N),N是列表长度
        new_dict[key] += my_list.count(val_in_dict_list) # my_list.count() 也是 O(N)

这两种方法都存在严重的性能问题。让我们分析其时间复杂度:

  1. 外层循环: 遍历 my_dict 的键值对,其次数与 my_dict 的键数量成正比。
  2. 内层循环: 对于 my_dict 的每个值(一个列表),遍历其内部元素。
  3. 最内层操作:
    • 在第一个示例中,直接遍历 my_list 进行比较。
    • 在第二个示例中,my_list.count(val) 或 val_in_dict_list in my_list 操作,对于Python列表来说,其时间复杂度是 O(N),其中 N 是 my_list 的长度。这是因为Python需要遍历整个列表来查找或计数元素。

综合来看,这种方法的时间复杂度大致为 O(K * V_avg * L),其中 K 是 my_dict 的键数量,V_avg 是 my_dict 中值列表的平均长度,L 是 my_list 的长度。在最坏情况下,如果这些长度都近似为 N,则总时间复杂度将达到 O(N^3)。这意味着当输入数据量增大时,程序的执行时间将急剧增加,变得不可接受。

macOS UI 自动化技能包 —— 用 Python 控制你的 Mac
macOS UI 自动化技能包 —— 用 Python 控制你的 Mac

让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限

下载

优化方案:预处理与字典查找

为了提高效率,我们可以采用“空间换时间”的策略:首先对 my_list 进行预处理,计算其中每个元素的出现次数,并将其存储在一个字典中。由于字典的查找和插入操作平均时间复杂度为 O(1),这将大大加快后续的计数过程。

优化算法的步骤如下:

  1. 预处理 my_list: 遍历 my_list,创建一个新的字典(例如 counts),记录 my_list 中每个唯一元素出现的次数。这一步的时间复杂度为 O(L),其中 L 是 my_list 的长度。
  2. 遍历 my_dict: 遍历 my_dict 的每个键值对。对于每个键,初始化其计数为0。
  3. 累加计数: 对于 my_dict 中每个键对应的列表中的元素,到步骤1中创建的 counts 字典中查找其出现次数,并累加到当前键的总计数中。由于字典查找是 O(1),这一步的效率非常高。这一步的总时间复杂度为 O(K * V_avg),其中 K 是 my_dict 的键数量,V_avg 是 my_dict 中值列表的平均长度。

纯Python实现

下面是基于上述优化思路的纯Python函数实现:

def count_nested_values(my_dict: dict, my_list: list) -> dict:
    """
    高效统计字典值中嵌套列表元素在主列表中出现次数的函数。

    参数:
    my_dict (dict): 键为字符串,值为字符串列表的字典。
    my_list (list): 包含字符串的主列表。

    返回:
    dict: 新字典,键为my_dict的键,值为对应元素在my_list中的总出现次数。
    """
    # 步骤1: 预处理 my_list,计算每个元素的出现次数
    # 使用字典存储,查找效率为 O(1)
    counts = {}
    for list_val in my_list:
        if list_val in counts:
            counts[list_val] += 1
        else:
            counts[list_val] = 1
    # 这一步的时间复杂度是 O(len(my_list))

    # 步骤2 & 3: 遍历 my_dict 并累加计数
    new_dict = {}
    for k, dict_val_list in my_dict.items():
        new_dict[k] = 0  # 初始化当前键的计数

        # 遍历 my_dict 值中的每个元素
        for item_in_dict_list in dict_val_list:
            # 在预处理的 counts 字典中查找元素出现次数
            # 字典查找是 O(1)
            if item_in_dict_list in counts:
                new_dict[k] += counts[item_in_dict_list]
            # 如果元素不在 counts 中,说明它在 my_list 中从未出现,计数为0,无需操作

    # 这一步的总时间复杂度是 O(len(my_dict) + 总的嵌套列表元素数量)
    # 因为遍历 my_dict 的键,然后遍历每个键对应的列表

    return new_dict

# 示例数据
my_dict = {'A': ['A', 'B'], 'B': ['C', 'D'], 'C': ['E', 'F']}
my_list = ['A', 'D', 'A', 'C', 'F', 'F']

# 调用函数并打印结果
result_dict = count_nested_values(my_dict, my_list)
print(result_dict)

性能分析

通过上述优化,算法的时间复杂度显著降低:

  1. 预处理 my_list: O(len(my_list))。
  2. 遍历 my_dict 并累加: O(len(my_dict) + sum(len(v) for v in my_dict.values())),即 O(my_dict 的键数量 + my_dict 中所有值列表的元素总数)。

因此,整个算法的最终时间复杂度是 O(len(my_list) + my_dict 的键数量 + my_dict 中所有值列表的元素总数)。这可以简化为O(N),其中N是输入数据(my_list和my_dict` 中所有元素)的总量。

与 O(N^3) 的原始方法相比,O(N) 的性能提升是巨大的,尤其是在处理大型数据集时。

使用 collections.Counter 简化预处理

Python 的 collections 模块提供了一个 Counter 类,可以更简洁地完成 my_list 的预处理步骤:

from collections import Counter

def count_nested_values_with_counter(my_dict: dict, my_list: list) -> dict:
    """
    使用 collections.Counter 高效统计字典值中嵌套列表元素在主列表中出现次数的函数。
    """
    # 步骤1: 使用 Counter 预处理 my_list
    counts = Counter(my_list) # 这一步的时间复杂度是 O(len(my_list))

    new_dict = {}
    for k, dict_val_list in my_dict.items():
        current_key_total_count = 0
        for item_in_dict_list in dict_val_list:
            # Counter 对象可以直接通过键获取计数,如果键不存在则返回 0
            current_key_total_count += counts[item_in_dict_list]
        new_dict[k] = current_key_total_count

    return new_dict

# 示例数据
my_dict = {'A': ['A', 'B'], 'B': ['C', 'D'], 'C': ['E', 'F']}
my_list = ['A', 'D', 'A', 'C', 'F', 'F']

# 调用函数并打印结果
result_dict_counter = count_nested_values_with_counter(my_dict, my_list)
print(result_dict_counter)

collections.Counter 在内部也是基于字典实现的,因此其性能特性与我们手动构建 counts 字典的方法相似,但代码更简洁易读。

注意事项与总结

  • 时间与空间的权衡: 优化后的解决方案通过引入一个中间字典 counts 来存储预处理结果,从而牺牲了一定的内存空间(存储 counts 字典)以换取显著的时间性能提升。在大多数实际应用中,这种权衡是值得的,因为时间效率通常更为关键。
  • 数据规模: 对于非常小的数据集,O(N^3) 的方法可能在实际运行时间上与 O(N) 方法相差无几,甚至因为代码简洁性而略快(因为避免了字典构建的开销)。但一旦数据规模稍大,性能差异将变得非常明显。
  • 可读性: 优化后的代码虽然比简单的三层嵌套循环稍微复杂一些,但其逻辑清晰,通过分步处理使得代码更易于理解和维护。

通过本教程,我们学习了如何识别和优化Python代码中的性能瓶颈,特别是涉及多层数据结构遍历和查找的场景。理解数据结构(如列表和字典)操作的时间复杂度是编写高效Python代码的关键。在处理类似问题时,优先考虑对数据进行预处理以降低后续操作的复杂度,通常能带来显著的性能提升。

热门AI工具

更多
讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

花生AI
花生AI Hot

一款AI视频创作工具,主要用于B站推出的AI视频创作工具,适合需要提升相关任务效率的用户。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

相关专题

更多
counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3528

2023.11.20

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

1838

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2924

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

6224

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

6089

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

7674

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

11574

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

5959

2025.07.29

Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

60

2026.10.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Uvicorn官方安装与入门手册
Uvicorn官方安装与入门手册

共0课时 | 0人学习

Python uv官方项目管理指南
Python uv官方项目管理指南

共0课时 | 0人学习

Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn