Python 数据结构

2.数据结构

  • 列表
  • 元组
  • 字典
  • 集合
  • 文本和字符序列
  • collection系列

  • 容器序列
    list,tuple,collections.deque 这些序列存放不同类型的数据
  • 扁平序列
    str,bytes,bytearray,memoryview,array.array 这类序列只能容纳一种类型
  • 可变序列
    list,bytearray,array.array, collections.deque, memoryview
  • 不可变序列
    tuple, str, bytes

列表

列表 能存放不同类型的元素,有序,可变序列,最基础最重要的序列。

'''创建列表的方式
1. 创建方式:[] 或 list()。
2. 列表的基本操作:索引index、切片 、追加append、删除del remove pop、长度len、循环for while、包含 x in obj[]、extend()、reverse()
'''
# 创建列表
list_test = ['aa',11,"##"]
print(list_test)
list_test_0 = list('abc')
print(list_test_0)

# 获取列表第二个元素
list_test[1]

# 列表切片
print(list_test[:1])
print(list_test[:-1])
print(list_test[1:2])

# 追加元素
list_test_0.append('bb')
list_test_0
['aa', 11, '##']
['a', 'b', 'c']
['aa']
['aa', 11]
[11]





['a', 'b', 'c', 'bb']
'''
列表推导是一种构建列表的方式
'''
symbols = '@#¥%'
codes = []
for symbol in symbols:
    codes.append(ord(symbol))
print("for循环:", codes)

codes = [ord(symbol) for symbol in symbols] # ord()返回对应的 ASCII 数值,或者 Unicode 数值
print("列表推导:" , codes)
for循环: [64, 35, 65509, 37]
列表推导: [64, 35, 65509, 37]
# 列表推导笛卡尔积
colors = ['black','white']
sizes = ['S','M','L']
tshirsts = [(color,size) for color in colors for size in sizes]
tshirsts
[('black', 'S'),
 ('black', 'M'),
 ('black', 'L'),
 ('white', 'S'),
 ('white', 'M'),
 ('white', 'L')]
'''
列表推导的作用只有一个:生成列表!
初始化元组,数组或其他序列类型,生成器表达式更好,它遵守迭代器协议,逐个产出元素,不是一次弹出所有的元素,节省内存。
生成器表达式 和列表推导语法相似,[] 换成()而已
'''
# 生成器表达式生成 元组 ,数组
symbols = '@#$'
tuple(ord(symbol) for symbol in symbols)

import array
array.array('I',(ord(symbol) for symbol in symbols))
array('I', [64, 35, 36])

元组

不可变的“列表”,可用于没有字段名的记录(同关系表的记录),有序,不可变序列。

'''
1. 创建:用小括号 ( ) 表示或者tuple(),
2. 元组与列表一样有基本操作:索引、切片、循环、长度、包含。 没有插入、删除某一元素的操作。
'''
tuple_test = ('a',1,[2,'b'])  # 元组中只有一个元素 (a,)须加逗号消除歧义
tuple_test

tuple('aa')
tuple(['c',3,4])
('c', 3, 4)
# 元组拆包
lax_coordinates = (33.22,-118.11)
city, year, pop, chg, area = ('Tykyo', 2003,32450,0.66,8014)  # 用元组的每个值分别赋值给变量 其实已是一种元组拆包的应用
traveler_ids = [('USA','32205855'),('BRA','CE342567'),('ESP','XDA205856')]
for passport in sorted(traveler_ids):
    print('%s/%s' % passport)

for country, _ in traveler_ids:  # 并不是对元组所有的元素都有兴趣,占位符 "_" 可以帮我们解决
    print(country)

# 用“*”来处理剩下的元素
# a, b,*rest = range(5)
# a,b,rest

# 嵌套元组拆包
mutil= [ ('a','b',1,(0.1,0.2)),('w','q',2,(0.3,0.4))]
fmt = '{:15} | {:9.4f}| {:9.4f}'
for n1, n2, n3, (x, y) in mutil:
    print(fmt.format(n1,x,y))
BRA/CE342567
ESP/XDA205856
USA/32205855
USA
BRA
ESP
a               |    0.1000|    0.2000
w               |    0.3000|    0.4000
'''
具名元组,又有称命名元组
collections.namedtuple 构建带字段名的元组和一个有名字的类,这对调试程序有很大的帮助。
'''
# card = collections.namedtuple('Card',['rank','suit'])
from collections import namedtuple
City = namedtuple('ty','name country  population coordinates') # 两个参数:类名,字段名。
tokyo = City('Tokyo','JP',36.933,(35.689722, 139.691667))
print(tokyo)
print(tokyo.population)
print(tokyo.coordinates)
print(City._fields) # 包含这个类的所有字段名称的元组
ty(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
36.933
(35.689722, 139.691667)
('name', 'country', 'population', 'coordinates')
  • 大部分情况下,除了跟增减元素相关的方法之外,元组支持列表的其他所有方法

切片

列表,元组,字符串 这类序列支持切片

# 切片和区间会忽略最后一个元素
l = [10,20,30,40,50,60,70]
print(l[1])
print(l[:2])
print(l[2:])
print(l[:3])
s='tensorflow'
print(s[::3])
print(s[::-2])
20
[10, 20]
[30, 40, 50, 60, 70]
[10, 20, 30]
tsfw
wlrse
# 给切片赋值 ,赋值右侧需要是可迭代的对象
l = list(range(10))
l[2:5] = [20,30]
print(l)
del l[5:7]
print(l)
[0, 1, 20, 30, 5, 6, 7, 8, 9]
[0, 1, 20, 30, 5, 8, 9]
# 对序列使用+ 和*  两者不修改原来的序列,构建一个全新的序列,
# python tutor 来查看python运行原理
l = [1,2,3]
print(l*3)
print(l)
print(l+[9,8,7])
[1, 2, 3, 1, 2, 3, 1, 2, 3]
[1, 2, 3]
[1, 2, 3, 9, 8, 7]
''' 
list.sort 和 内置函数sorted
list.sort就地改动原来的列表,不会产生新表,返回None。sorted正好相反
两者都有可选的关键字参数:reverse, key
'''
fruits = ['grape','raspberry','apple','banana']
sorted(fruits)
sorted(fruits, reverse=True) # 降序排序
sorted(fruits, key=len) # 按照元素长度 排序
['grape', 'apple', 'banana', 'raspberry']
  • 如1000万浮点数 数组处理的很好,频繁对序列先进先出 deque(双端队列)速度很快,检查元素是否出现在集合中 set 更合适
'''
数组array.array
如对于1000万个浮点数,数组处理要好的多,
序列只包含数字,array.array 比list 效率更高
操作:.pop , .insert , .extend , .frombytes , .tofile
'''
from array import array 
from random import random
floats = array('d',(random() for i in range(10**7))) # 'd' 代表浮点数类型, 第二个参数可迭代对象是生成器的表达式
floats[1]
0.9267320195098516

字典

能够直接将一个对象映射到另一个对象,被存储的对象为值,被索引的对象为键,即键值对。
使用dict{}构造函数和{}快捷语法(较常用)来构造一个字典,如dic = {‘k1’:’v1’} 等价 dic=dict(k1=’v1’)。
基本操作:新增d[key]、删除del d[key]、键值对keys,values,items、循环、长度、fromkeys()

字典使用了高效的哈希算法,内部的键值对之间是无序的。字典循环时,默认循环key。


  • 可散列的数据类型
    若一个对象是可散列的,在他的生命周期汇总,它的散列值是不变,可用hash()方法实现
    原子不可变数据类型 如str、bytes和数值类型 ,都是可散列的类型。
    元组 中所有的元素是可散列的,该元组才是可散列的。
'''
创建:dict{}构造函数和{}快捷语法(较常用)来构造一个字典,如dic = {'k1':'v1'} 等价 dic=dict(k1='v1')。
'''
a = dict(one=1,two=2,three=3)
print(a)
b = {'one':1,'two':2,'three':3}
print(b)
c = dict(zip(['one','two','three'],[1,2,3]))
print(c)
d = dict([('two',2),('one',1),('three',3)])
e = dict({'three':3,'one':1,'two':2})
a==b==c==d==e
{'one': 1, 'two': 2, 'three': 3}
{'one': 1, 'two': 2, 'three': 3}
{'one': 1, 'two': 2, 'three': 3}





True
'''
字典推导  
可以从任何以键值对作为元素的可迭代对象中构建出字典。
'''
DIAL_CODES = [
    (86, 'China'),(91, 'India'),(1, 'United States'),(62, 'Indonesia'),(55,'Brazil'),(92,'Pakistan'),(880,'Bangladesh')
]
country_code = {country: code for code, country in DIAL_CODES} # 字典生成器
print(country_code)
{'China': 86, 'India': 91, 'United States': 1, 'Indonesia': 62, 'Brazil': 55, 'Pakistan': 92, 'Bangladesh': 880}
# setdefault 处理找不到的键
my_dict={'a':1,'b':2}
new_value=3
my_dict.setdefault('c', []).append(new_value)
# 等价于
if 'c' not in my_dict:
    my_dict['c'] = []
my_dict['c'].append(new_value)
# 后者进行了两次查询,若键值不在 就要查三次;setdefault只需要查一次。
print(my_dict)
{'a': 1, 'b': 2, 'c': [3]}
# defaultdict 处理找不到的键的一个选择
dd.defaultdict(list)
# 表达式dd['new-key']按照步骤:
# 调用list()类建立一个新列表
# 把这个新列表作为值,‘new_key’作为它的键,放到dd中
# 返回这个列表的引用


# 特殊方法 __missing__ 
# 当有类继承了dict类,在__getitem__找到不到键的时候,会自动调用__missing__,而不是抛出异常。

字典的变种

  • collectinos.OrderedDict
    这类型在添加键的时候,会保持顺序,键的迭代次序总是一致的。

  • collections.ChainMap
    该类型可容纳数个不同的映射对象,然后进行键查找操作的时候,这些对象会被当作一个整体被逐个查找。

  • collecions.Counter
    这个映射类型会给键准备一个整数的计数器,每次更新一个键的时候都会增加这个计数器。

  • collections.UserDict
    是让用户继承写子类的。

'''
不可变的映射类型:
之前见过不可变的序列,是否存在不可变的字典类型。
python3.3开始,types模块映入了一个封装类名MappingProxyType, 传给此类映射,会返回一个只读的映射视图,但是动态的(可以操作改动)
'''
from types import MappingProxyType
d = {1:'A'}
d_proxy = MappingProxyType(d)
# d_proxy[2] = 'B'  #抛出异常,不支持修改,
d[2]='B' # 对原来的字典 d 修改,发现MappingProxyType 的也被修改了
d_proxy
mappingproxy({1: 'A', 2: 'B'})

集合

  1. 集合的本质就是许多唯一对象的集合,集合可以用于去重。在爬虫中使用避免爬出重复的数据。
  2. 集合使用set()构造函数,或{}花括号(这里用逗号分隔值,不同与字典需要用冒号来分隔键值)
  3. 集合和字典是无序的,所以其不能通过索引查找,都是使用基于哈希的底层数据结构。
  4. 使用集合的目的:将全部事物分为两组:“属于集合的事物”和“不属于集合的事物”
  5. 将集合遍历很简单,但是对集合排序,则需要转换为列表。
'''
创建:set()构造函数,或{}花括号(这里用逗号分隔值,不同与字典需要用冒号来分隔键值)
'''
l = ['spam','spam','eggs','spam']
set(l)

# '''
# 以下{}创建形式,创建一个空集 使用不带任何参数的set(),但如果用{}会创建一个空字典 
# '''
# se = {'span',1,'asd'} #看起来和数学形式一摸一样能够
# se
{'eggs', 'spam'}
'''
字典中散列表
散列表本质是稀疏矩阵,散列表里的单元叫作表元bucket,dict的散列表中,每个键值都占用一个表元,表元:1对键的引用,2对值的引用。
表元大小一样,通过偏移量来读取某个表元。
对象存入到散列表中,首先要计算这个元素键的散列值。hash()方法

散列表算法
为获取my_dict[search_key]背后的值,python会调用hash(search_key)计算search_key的散列值,把这值最低的几位数字当作偏移量,在散列表里查找表元。
若表元是空的,则返回keyerror。若不为空,表元里会有一对 found_key:found_value。会被检验 search_key == found_key是否为真,相等的话返回found_value。

散列冲突
search_key 和found_key 不匹配,就称为散列冲突。

对字典的迭代并修改
最好:首先对字典迭代,得出需要添加的内容,把这些内容放在一个新的字典里, 迭代结束后再对原有的字典进行修改。

set的实现及导致的结果
set的实现需要依赖散列表,在散列表里只存放元素的引用(字典里是只存放键)。
集合中的元素必须是可散列的
集合很消耗内存
集合中判断元素的存在是非常迅速的
元素的次序取决于被添加到集合的次序
往集合添加元素,可能会改变集合中已有元素的次序
'''
'\n字典中散列表\n散列表本质是稀疏矩阵,散列表里的单元叫作表元bucket,dict的散列表中,每个键值都占用一个表元,表元:1对键的引用,2对值的引用。\n表元大小一样,通过偏移量来读取某个表元。\n对象存入到散列表中,首先要计算这个元素键的散列值。hash()方法\n\n散列表算法\n为获取my_dict[search_key]背后的值,python会调用hash(search_key)计算search_key的散列值,把这值最低的几位数字当作偏移量,在散列表里查找表元。\n若表元是空的,则返回keyerror。若不为空,表元里会有一对 found_key:found_value。会被检验 search_key == found_key是否为真,相等的话返回found_value。\n\n散列冲突\nsearch_key 和found_key 不匹配,就称为散列冲突。\n\n对字典的迭代并修改\n最好:首先对字典迭代,得出需要添加的内容,把这些内容放在一个新的字典里, 迭代结束后再对原有的字典进行修改。\n\nset的实现及导致的结果\nset的实现需要依赖散列表,在散列表里只存放元素的引用(字典里是只存放键)。\n集合中的元素必须是可散列的\n集合很消耗内存\n集合中判断元素的存在是非常迅速的\n元素的次序取决于被添加到集合的次序\n往集合添加元素,可能会改变集合中已有元素的次序\n'

文本序列和字节序列

有话说:人类使用文本,计算机使用字节序列。

你可能感兴趣的:(Python)