跳到主要内容 Python 常见数据结构详解 | 极客日志
Python 算法
Python 常见数据结构详解 Python 常见数据结构包括元组、列表、字典和集合。元组不可变适合存储固定数据;列表可变支持频繁修改;字典基于键值对实现快速查找;集合用于去重和运算。文章详细介绍了各结构的创建、访问、修改方法及性能特点,帮助开发者根据场景选择合适的数据结构以提升代码效率。
Python 常见数据结构详解
1. 简单/基础数据结构
1.1 元组
元组是 Python 中一种不可变的数据结构,以元组为数据结构存储的数据内容较为稳定,不会轻易发生变动。因此,元组适合存储结果等数据内容。总而言之,元组一经创建便不会改变,改变的主要方式是在原元组的形式上创建新的元组。
函数、实例化类、调用实例化类中的方法都是使用 (),我称之为函数的元组调用格式。
如何成为元组?
从 list 转换为元组 :tuple(list)
从老元组到元组 :切片复制前后的变量指向不同内存地址或者是 tuple(for i in old_tuple),这种复制方式内容前后为两个内存地址。(在 Python 中 用来判断两个变量的内容是否相同, 用来判断两个变量是否来自于相同的内存地址)
==
is
两个元组拼接成一个新元组 :该新元组与老元组不在同一个内存地址。新元组如果是单个元素应该 (element,)
如何转换元组数据?
元组与 list 之间的转换 :tuple(list) or list(tuple)
元组与集合之间的转换 :tuple(set) or set(tuple)
如何访问元组?
索引 :通过索引访问元组中的元素,如 tuple[0]
切片 :通过切片访问元组中的子元组,如 tuple[0:2]
如何编辑元组? 由于元组是不可变对象,因此改变数组的方式是创建新的元组,而新元组继承了老元组的部分内容然后添加了一些内容。例如:
new_tuple = old_tuple[0 :2 ] + (3 ,) + old_tuple[3 :]
元组和其他数据结构存在什么联系?
enumerate(list) :会转换 [(index, value)] 的可迭代对象(查看数据的格式,通过 type()),想要转换成 list 的话,会需要 list(enumerate(list))
dictionary.items() :会将字典变成 [(index1, value1), (index2, value2)….] 的可迭对象,这种对象不是某一种数据结构而是一种迭代器结构。list(iteration) 会将该迭代对象转换为嵌套元组的 list
zip(list) :其中的 list 是 [(index1, value1), (index2, value2)…..],zip 函数配合 dict() 可将 list 转换为一个字典
迭代器和生成器 可迭代对象和 range 之间的关系与区别。插入迭代器和生成器的知识,用来解释上述的 enumerate、zip、.items() 等函数。
首先是常见的可迭代对象:list、set、dict、tuple、字符串、range。这些可迭代对象转换为迭代器的方式为 iter(list or set or dict or tuple)。之后每调用一次 next 便会访问一个迭代器中的数值。
yield 为关键词组成的生成器,其为特殊的迭代器。特殊的地方在于该迭代器访问的不是一个元素而是以 yield 为标志截断的代码行。较为普遍的迭代器为 [element1, element2, element3….],生成器为 [yield 之后的代码+yield 之前的代码,yield 之后的代码+yield 之前的代码,yield 之后的代码+yield 之前的代码]。
另外 for 循环的逻辑就是调用 iter() 生成迭代器,然后不断地调动 next,直到出现 StopIterationError。
1.2 列表 在 Python 程序中,列表通常作为存储、访问数据的容器。无论是简单的数据结构还是复杂的数据结构,在访问数据时通常会用到 [],我称之为 list 访问方式。list 与上述的 tuple 相反,它是一种可变的数据结构。
字符串可以分解成列表,列表中的字符串可以拼接成字符串。使用 ".join()" 的方法。
第一方面是从列表本身的格式、编辑、访问角度了解列表
列表中元素的格式有限制吗?
列表中的元素无限制 :既可以是不同数据类型的元素,又可以是元组、字典、列表等数据结构。
当列表中都是元素的时候,元素的数据类型存在两种情况:
存在上述两种情况时,统一列表中元素数据类型的操作是:
float_list = [float (i) for i in old_list]
int_list = [int (i) for i in old_list]
str_list = [str (i) for i in old_list]
其中 map 返回的是一个迭代器,可以使用 list 或 next 进行访问,map 里面的参数 function 是一个函数名,既可以是一个自定义的,又可以是一个底层的函数例如 str、int、float 或者是一个匿名函数 lambda x: x**2。
当列表中的元素是元组、字典、集合等可迭代对象的时候,对于访问会存在一些难度。当然这种数据结构的混合其实就是 dataframe、numpy 中的数组。Dataframe 的结构是 {column1: {index1: value1, index2: value2}}。Numpy 中的数组结构是 [[][][]] 当然 numpy 中的数组结构对于每一个子列表的形状大小有要求。
如何有条件的生成一个列表?
生成特殊值的列表 :不像 numpy 一样有很多现成的函数可以实现,因此要想获得一个你想要的列表,需要借助函数和迭代器。从使用角度,一般会生成两种列表。一种列表内部全部是固定值,另一种列表基于另一个列表或者一些特定的函数。
list1 = [0 for _ in range (0 )]
list1 = [lambda x: 2 * x for x in list0]
normal_list = [random.gauss(mu, sigma) for _ in range (size)]
binomial_list = [random.binomialvariate(n, p) for _ in range (size)]
如何访问列表? 元素 Element1 Element3 Element5 Element7 顺索引 0 1 2 3 逆索引 -4 -3 -2 -1 顺切片 0 1 2 3 逆切片 -5 -4 -3 -2
如何访问列表中具有特定值的元素? 从原列表删除特定的值 :在删除这些特定值之前,需要收集这些值的在原列表对应的索引。
index_value_dict = list (enumerate (old_list))
index_list = [key for key, value in index_value_dict if value == target_value]
end_list = [old_list.pop(index) for index in index_list]
new_list = [i for i in old_list if i == target_value]
列表有浅复制和深度复制这一回事吗?
列表的复制 :直接赋值不是拷贝。拷贝分为浅拷贝和深拷贝,浅拷贝前后列表对象本身对应的内存地址不相同,但列表对应的元素的内存地址相同。
new_list = old_list.copy()
new_list = old_list[:]
import copy
new_list = copy.deepcopy(old_list)
如何删除列表中特定的值?
方式 1 :删除 list 中的一些特定索引值 del list[index or index1:index2]
方式 2 :删除 list 中的一些特定索引并返回这些索引对应的值:list.pop(index) 或者 list.pop() 默认删除 list 里面的最后一个值
方式 3 :删除 list 中的特定值:list.remove(value) 默认情况下会删除 list 中的第一个 value 值
具体的应用场景:对于'删除列表中满足条件值'的问题,由于调用 del、pop、remove 都是一个元素一个元素的删除,但是删除一个元素之后,整个列表的值和索引又会发生改变。
第一种情况 :删除一个索引列表,如果采用 pop 或者 del,删除的过程需要对索引列表进行排序,sorted(index_list) 以此来避免删除对于列表发生变化的影响
第二种方式 :将 list 转换成 dictionary,使用 list(enumerate(target_list))。然后 for 循环保留正确的 index
如何在列表的特定位置添加一个值?
list.append() :默认末尾添加元素,append 方式可以添加各种格式的元素,既可以是列表,也可以是 element
list.extend() :末尾添加很多元素
list.insert(index, value) :在指定位置插入元素
如何按照一个分布或者默认的长度生成一个列表?
list = [i for i in range (start, end, step)]
list = [lambda x: source**x for x in range (times)]
ones_list = [1 for _ in range (times)]
normal_list = [random.normal(mu, sigma) for _ in range (times)]
List 如何参与数学运算? 常见的数乘列表表示列表中元素的数次复制,数加列表会出现 TypeError: unsupported operand type。
List 可以通过 count(list) 生成 unique value 和其对应的 count 吗?以及列表的排序
排序 :一种排序是直接改变原列表 sort,另一种排序是在原列表中排序并进行复制 sorted
unique value 和 count :得到每一个 unique value 的方式是将原列表转换成集合,set = set(list),通过 list 计算每一个 value 的 count 的方式是 list.count(value)
如何更换列表中的某一位置的值?
1.3 字典 字典有 key 和 value 两项构成,key 的格式必须是不可变对象也就是不可哈希对象,key 的值可以是整数、浮点数、字符串、元组(元组内不存在列表这种不可哈希对象),value 可以是任何格式的值可以是字典、列表、集合、数组等等。在添加元素的时候,如果新添加的元素与老元素的名字重合,则新添加的元素取代老元素。
如何创建字典?
方式 1 :采用 {}
方式 2 :采用 dict()
如何向字典中添加元素? 如果 key 值在字典中已经存在,则会使 value 值覆盖原有的 value 值。如果 key 值在字典中没有存在,则会向字典中添加 key-value 对。
如何按照 key 值删除元素? 通过指定 key 值删除 key-value 对的方式主要有:
del dict['key']
dict.pop('key')
另一个是根据 key-value 对的 index 值,进行删除。这个可能需要一个 for 循环即可解决。具体的解决方式如下:
k = 0
for key, _ in dict .items():
if k == index:
del dict [key]
else :
k += 1
如何遍历字典的 key 值、value 值以及同时遍历 key 和 value 的值?
访问 key 值 :dict.keys()
访问 value 值 :dict.values()
同时访问 key 和 value 值 :dict.items()
反转字典的键和值 字典的键不含有重复值,每一个键都是唯一的。如果进行反转,可能会出现值存在重复值和不存在重复值两种情况。
对于不存在重复值这种情况,反转的方式主要有以下两种:
new_dict = {value: key for key, value in dict .items()}
new_dict = dict (zip (old_dict.values(), old_dict.keys()))
对于存在重复值的情况,需要将重复的 value 值对应的 key 收集进列表当中:
new_dict = {}
for key, value in dict .items():
if value in new_dict:
if isinstance (new_dict[value], list ):
new_dict[value].append(key)
else :
new_dict[value] = [new_dict[value], key]
else :
new_dict[value] = key
1.4 集合 谈起集合,首先想到的便是 set(list),会得到一个唯一值的集合。对这个集合的操作有 |(并集)&(交集)。
集合的基本操作
set1 = {1 , 2 , 3 }
set2 = set ([3 , 4 , 5 ])
union_set = set1 | set2
intersection_set = set1 & set2
difference_set = set1 - set2
symmetric_difference_set = set1 ^ set2
集合的其他操作
set1.add(4 )
set1.remove(2 )
set1.pop()
set1.clear()
if 1 in set1:
print ("1 is in set1" )
2. 数据结构的选择和应用场景
2.1 如何选择合适的数据结构? 数据结构 特点 适用场景 列表 有序、可变、允许重复元素 存储有序数据、需要频繁修改的数据 元组 有序、不可变、允许重复元素 存储固定数据、函数返回多个值 字典 无序、键值对、键唯一 存储映射关系、快速查找数据 集合 无序、可变、不允许重复元素 去重、集合运算
2.2 数据结构的性能对比 操作 列表 字典 集合 访问元素 O(1) O(1) O(1) 查找元素 O(n) O(1) O(1) 插入元素 O(1) 或 O(n) O(1) O(1) 删除元素 O(1) 或 O(n) O(1) O(1)
3. 总结 Python 提供了丰富的数据结构,每种数据结构都有其特点和适用场景。掌握这些数据结构的使用方法和性能特点,对于编写高效、优雅的 Python 代码至关重要。
在实际编程中,需要根据任务的需求选择合适的数据结构:
如果需要存储有序的数据,并且需要频繁修改,选择列表
如果需要存储固定的数据,或者函数需要返回多个值,选择元组
如果需要存储映射关系,或者需要快速查找数据,选择字典
如果需要去重,或者进行集合运算,选择集合
同时,还需要注意数据结构的性能特点,避免在性能敏感的场景中使用不合适的数据结构。例如,在需要频繁查找元素的场景中,使用字典或集合比使用列表更高效。
通过本文的介绍,相信你对 Python 中的常见数据结构有了更深入的了解。在实际编程中,需要根据任务的需求选择合适的数据结构,以提高代码的效率和可读性。
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online