数据结构:数据结构是计算机存储数据和组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。在python中主要的数据类型统称为容器。
而序列(如列表、元组)、映射(如字典)、集合(set)就是python中最主要的容器。
序列:成员有序的排列,并且可以通过下标和偏移量访问到他的一个或几个成员的类型统称为序列。他是最基本的数据类型。Python中内建的序列有6种:列表、元组、字符串、Unicode字符串、buffer对象和xrange对象。下面重点介绍列表和元组。
列表
列表:是储存和处理一组有序项目的数据结构。
特点 : ①有序排列
②原列表可以改变的。这是它区别于字符串和元组的最重要的特点
重点:将字符串转换为列表用split,将列表转化为一组字符串用join。
表达式:方括号[ ],每项用逗号(,)隔开。
常用的函数方法:最基本的方法:增删改查。
举例:name =["a","b","c"]
(1)打印列表中的元素c。print(name[2])
(2)打印列表中的元素b,c。print(name[1:3])
(3)打印列表中的最后一个项目。print(name[-1])
(4)打印列表中的最后两个项目。print(name[-2:])
(5)添加有四种方法。
1# name.append("d") ,只能在列表中添加一个元素且只能添加在末尾。
2# name.extend(列表名,元组名等) ,可以添加一个可迭代对象,仅仅是一个,可迭代对象包括元祖,列表,字典,字符串等,多个字符串要放在一个元祖或列表中、且只能添加在末尾。注意最后形成的还是列表。
a = [1, 2, 23, 4]
b = (5, 6, 7, 8, 9)
a.extend(b) #迭代的添加
print(a)
结果:
[1, 2, 23, 4, 5, 6, 7, 8, 9]
3#name.insert(index,obj), index 想插入的索引号,新的元素将成为该索引号上的元素。obj想要插入的元素。
4#:列表间可以直接相加“+”,但是这种方法不节省内存,因为多开辟了一个内存空间。
举例:
li1=[1,2,3,4] li2=[5,6,7] li3=li1+li2
结果:
[1, 2, 3, 4, 5, 6, 7] 迭代着添加
(6)替换。 name[1]="x"
(7)删除。有三种方法:
① del name[index] 可以切片只有它可以切片剩余的都不可以切片. del name 直接删除列表
② name.remove("要删除的元素”) #如果有多个元素b,默认删除第一个元素b,无返回值 ,没有该元素会报错。
③ name.pop(index) #函数用于移除列表中的一个元素(如果括号里没有数字则默认删除最后一个元素),并且返回被删除的该元素。如果要显示被删除的元素可以这样写。print(name.pop(index)) 有返回值。
a = [1, 2, 23, 4] c=a.pop(2) print(a) print(c)
结果:
[1, 2, 4]
23
(8)查找。name.index("要查找的元素") #结果为要查找的元素的索引号。当存在时返回元素的索引,不存在时报错。列表的方法中没有find(),不要和字符串混淆。
(9)统计。name.count("要查找的元素") #结果为显示列表里有查找的元素的个数。列表count不能切片,字符串里能切片
(10)清除列表。name.clear()
(11)反转列表。name.reverse()。反转字母或数字。还可以用切片来反转[::-1]
(12)列表永久排序。name.sort()。只能是数字或字母不能是字母和数字,如果要排要按ASCII,sort(reverse=True)=倒序.
list=[1,5,3,4,2] list.sort(reverse=True) print(list) #排序加反转
结果:
[5, 4, 3, 2, 1]a
临时排序: sorted(a),这个可以用在所有的可迭代对象中,
a=[2,3,2,6,5] print('临时排序',sorted(a)) print('a的值',a)
结果:
临时排序 [2, 2, 3, 5, 6]
原来的值 [2, 3, 2, 6, 5]
(13)复制。Python中的复制其实有五种形式。
①赋值。在python中赋值。其实就只在内存开辟了一个空间,并没有新建内存地址,还是用的相同的内存地址。所以a变,B就变。,也可以说是引用的传递,只是引用变了,然而值却没有变.
在这里我们要补充一点知识:
对于python而言,python的一切变量都是对象,变量的存储,采用了引用语义的方式,存储的只是一个变量的值所在的内存地址,而不是这个变量的只本身。 #引用语义 引用语义:在python中,变量保存的是对象(值)的引用,我们称为引用语义。采用这种方式,变量所需的存储空间大小一致,因为变量只是保存了一个引用。也被称为对象语义和指针语义。 #值语义 值语义:有些语言采用的不是这种方式,它们把变量的值直接保存在变量的存储区里,这种方式被我们称为值语义,例如C语言,采用这种存储方式,每一个变量在内存中所占的空间就要根据变量实际的大小而定,无法固定下来。
a=[1,2,4,5,6,7] ###a必须是可变类型,如果是不可变的,是行不通 b=a a.append(8) print("a",a,id(a)) print("b",b,id(b))
结果:
a [1, 2, 4, 5, 6, 7, 8] 1518265683848
b [1, 2, 4, 5, 6, 7, 8] 1518265683848
但是有特例注意注意:字符串的原字符串是不可变得,如果要对元字符串的内容改变,是要重新开辟内存地址的。所以这个方法是不适合字符串的。但是对于列表这种可变数据类型来说就可以.
l="alex" m=l print("l",id(l)) print("m",id(m))
结果:
l 2147932168576
m 2147932168576
②浅复制(copy)。
对于浅copy来说,复制第一层时创建了新的内存地址,而从第二层开始都是指向的被复制那层的内存地址。所以对与第二层乃至更深的层次来说,和原列表保持一致。
范例:第一层:
c=[1,2,4,[100,103,105],6,7] d=c.copy() c.append(666) print("c",c,id(c)) print("d",d,id(d))
结果:
c [1, 2, 4, [100, 103, 105], 6, 7, 666] 1487569307720
d [1, 2, 4, [100, 103, 105], 6, 7] 1487569307784
第二层:
a=[1,2,4,[100,103,105],6,7]
b=a.copy()
a[3].append(666)
print("a",a,id(a[3])) #注意是要查看谁的ID地址,而不是查看a的ID
print("b",b,id(b[3]))
结果:
a [1, 2, 4, [100, 103, 105, 666], 6, 7] 1195850256264
b [1, 2, 4, [100, 103, 105, 666], 6, 7] 1195850256264
③相当于浅复制的例子。切片同时省略起始索引和中止索引。如b=a[:]。
④深复制(deepcopy)。开辟了新的内存地址.对与深copy,两个是对立的,改变任何一个元素,另一个不会改变。我要复制一个文件,原文件和新文件没有半毛钱的关系.
第一个例子:
1 mport copy 2 a=[1,2,3,4,["a","b",["x","z"]]] #原始对象 3 b=a #赋值 4 c=copy.copy(a) #浅复制 5 d=copy.deepcopy(a) #深复制 6 e=a[:] #另一种复制方式,它不属于copy模块下,也是一种浅复制 7 a.append("A") #第一层变动 8 a[4][2].append("C")#第三层变动 9 print("a=",a) 10 print("b=",b) 11 print("c=",c) 12 print("d=",d) 13 print("e=",e)
得到的结果为:
1 a= [1, 2, 3, 4, ['a', 'b', ['x', 'z', 'C']], 'A'] 2 b= [1, 2, 3, 4, ['a', 'b', ['x', 'z', 'C']], 'A'] #一点都不忠诚,a变他就变 3 c= [1, 2, 3, 4, ['a', 'b', ['x', 'z', 'C']]]#只忠诚第一层 4 d= [1, 2, 3, 4, ['a', 'b', ['x', 'z']]]#完全忠诚 5 e= [1, 2, 3, 4, ['a', 'b', ['x', 'z', 'C']]]#和c一样只忠诚第一层
第二个例子:
c=[1,2,4,[100,103,105],6,7] d=copy.deepcopy(c) c.append(666) print("c",c,id(c)) print("d",d,id(d))
结果:
c [1, 2, 4, [100, 103, 105], 6, 7, 666] 2763573379336
d [1, 2, 4, [100, 103, 105], 6, 7] 2763573379272
第三个例子:
import copy a=[1,2,4,[100,103,105],6,7] b=copy.deepcopy(a) a[3].append(666) print("a",a,id(a)) print("b",b,id(b))
结果:
a [1, 2, 4, [100, 103, 105, 666], 6, 7] 2763573320840
b [1, 2, 4, [100, 103, 105], 6, 7]
补充一个函数:join() 这个函数不是列表特有的。链接字符串数组,将字符串,列表,元组等可迭代对象中的元素以指定的特殊符号字符(分隔符)连接生成一个新的字符串。
结构为:“连接符”.join(可迭代对象)
例子:
li = ["alex","eric","rain"] temp="_".join(li) print(temp)
结果为:
alex_eric_rain
列表易错题目:
通过对li列表切片得到新的列表为["c"]
li=[1,3,2,"a","b","c"] print(li[-1]) print(li[-1:])
结果:
c ['c'] #注意对列表切片得到的是列表,对列表取下下标得到的是字符串
元组
元组:
元组用来将多祥的对象集合在一起,它也是序列,和列表类似只不过,元组和字符串一样是不可变的,即你不能修改元组。但是元组还有另外一个和字符串不同的特性儿子不能改,孙子可以改,
作用:用户希望他的数据不被改变,能够安全的采用一组数据。
语法形式:P=("a","b"," c","d")。用括号括起来,每个元素用逗号隔开。
它的函数方法只有count和index两种,用法和list一样。可以切片,循环。可迭代对象。
注意:元组的儿子不能替换但是孙子可以替换
题目要求:
- 把"xiaoli"替换成"小李” #这个是会报错的,因为元组的儿子不能被替换。
- 把“太白”替换成“taibai"
- 把“小红”替换成”xiaohong"#这个会报错因为元组的儿子是元组然后它的儿子也不能替换,凡是直系亲属都不可以。
li=(1,"xiaoli",3,4,[1,2,"太白","alex"],("小红","小白")) li[4][2]="taibai" print("li2",li)
结果:
li2 (1, 'xiaoli', 3, 4, [1, 2, 'taibai', 'alex'], ('小红', '小白'))
注意:还有一点:当元组内只有一个一个元素时要加逗号(,)
由圆括号包裹的一个单一元素首
先被作为分组操作,而不是作为元组的分界符。一个变通的方法是在第一个元素后面添一个逗
号(,)来表明这是一个元组而不是在做分组操作。具体什么是分组操作,我也不清楚
a=("你",) b=("你") print(type(a),a) print(type(b),b)
结果:
<class 'tuple'> ('你',) <class 'str'> 你
元组比较大小时,只比较第一个元素,如果元组1中的第一个元素<元组二中的第一个元素,name元组一<元祖二,当判断等于时,必须所有的元素东等于才会得到True。
print((2, 2) == (2, 2,)) print((3, 2) > (2, 8)) print((1, 5) > (2, 8))
结果:
True
True
False
list()
该方法是做项目遇到的,
该方法有两个作用:
第一个:将集合或列表转换为列表:
b = {"1","2","3"} print(list(b))
c = ("1","2","3")
print(list(c)
#结果为:['1', '2', '3']
第二个作用:当空列表用
print([]==list()) print(list()) #结果: TRUE []
字典
字典:它是唯一属于映射类型的。字典有键和值组成,键是唯一的键,但是值不是唯一的可以有多个。键必须是可哈希的(不能改变的数据类型:字符串,元组(元组内只包含数组和字母的组合才行),布尔值,数字)。不可哈希:列表,字典,集合。
特点:
1.无序它不属于序列。
2.数据关联性。
3.键唯一性且必须是可哈希的,
4.查找和插入的速度快,不会随着key的增加而变慢。
请务必注意,dict内部存放的顺序和key放入的顺序是没有关系的。
和list比较,dict有以下几个特点:
- 查找和插入的速度极快,不会随着key的增加而变慢;
- 需要占用大量的内存,内存浪费多。
而list相反:
- 查找和插入的时间随着元素的增加而增加;
- 占用空间小,浪费内存很少。
所以,dict是用空间来换取时间的一种方法。
dict可以用在需要高速查找的很多地方,在Python代码中几乎无处不在,正确使用dict非常重要,需要牢记的第一条就是dict的key必须是不可变对象。
这是因为dict根据key来计算value的存储位置,如果每次计算相同的key得出的结果不同,那dict内部就完全混乱了。这个通过key计算位置的算法称为哈希算法(Hash)。
要保证hash的正确性,作为key的对象就不能变。在Python中,字符串、整数等都是不可变的,因此,可以放心地作为key。而list是可变的,就不能作为key
增:有两种方法。
1.直接修改。如果里边没有,直接添加进字典。如果里边有相同的键会覆盖掉。
ic = {'k1': "v1", "k2": "v2", "k3": [11,22,33]} dic["k1"]="vv" print(dic)
结果:
{'k1': 'vv', 'k2': 'v2', 'k3': [11, 22, 33]}
2.setdefault. 如果里边没有,直接添加进字典。如果里边有相同的键,不会添加进字典,保持原来的不变。
dic = {'k1': "v1", "k2": "v2", "k3": [11,22,33]} dic.setdefault("k3","kk") print(dic)
结果:
{'k1': 'v1', 'k2': 'v2', 'k3': [11, 22, 33]}
注意看,我们要把kk添加到k3中怎么办?这就用到了setdefault另外一个知识
dict.setdefault(key, default=None),当键不存在时,使用默认值
dic = {'k1': "v1", "k2": "v2", "k3": [11,22,33]} dic.setdefault("k3",[]).append("kk") print(dic) #结果:{'k1': 'v1', 'k2': 'v2', 'k3': [11, 22, 33, 'kk']}
删:只有3个。
1.pop:按键删除,找到会返回删除内容。找不到会报错。有返回值。
print(dic.pop("key") ) 输出返回值
2.dic.clean():清空字典
3.del dic[key]
dic = {'k1': "v1", "k2": "v2", "k3": [11,22,33]} del dic["k1"] print(dic)
结果:
{'k2': 'v2', 'k3': [11, 22, 33]}
改
有两种:
1.直接赋值。dic[key]=value
2.update()
方法用于将dict2
的键值对添加到dict
。此方法不返回任何内容。有相同键的直接覆盖,没有的直接添加。
dic1 = {'k1': "v1", "k2": "v2", "k3": [11,22,33]} dic2 = {'k1': "v6", "k8": "v2"} dic1.update(dic2) print(dic1)
结果:
{'k1': 'v6', 'k2': 'v2', 'k3': [11, 22, 33], 'k8': 'v2'}
查:
1.直接查。print(dic["key"])
2.print(dic.get("key")) ,不存在时返回none,返回值可以自己设置。
3. dic.keys(),会得到一个包含所有key的列表。注意并不是一个真正意义上的列表(因为它不支持切片和索引取值),如果要转化真正的列表只需要这样list(dic.keys()),就可以了
4.dic.values(),会得到一个包含所有value的列表。
5.dic.items(),会的到一个包含所有value和key 的列表,####不建议这么获取字典的值和键,因为这样占内存,应该用以下这种方法来获得。
dic1 = {'k1': "v1", "k2": "v2", "k3": [11,22,33]} for key in dic1: print(key,dic1[key])
结果为:
k1 v1
k2 v2
k3 [11, 22, 33]
dic1 = {'k1': "v1", "k2": "v2", "k3": [11,22,33]} print(dic1.keys()) print(dic1.values()) print(dic1.items())
结果:
dict_keys(['k1', 'k2', 'k3']) dict_values(['v1', 'v2', [11, 22, 33]]) dict_items([('k1', 'v1'), ('k2', 'v2'), ('k3', [11, 22, 33])])
for 循环的特殊的用法:
dic1 = {'k1': "v1", "k2": "v2", "k3": [11,22,33]} 不建议用这种方法来获取键和值 for key,value in dic1.items(): print(key,value)
结果:
k1 v1
k2 v2
k3 [11, 22, 33]
如何比较两个字典的大小?
1.字典中的键的个数越多,这个字典就越大。
2.如果键的个数相同,则比较字键在,还没验证
dict()函数
Python 字典 dict() 函数用于创建一个新的字典。
# !/usr/bin/python3 dict0 = dict() # 传一个空字典 print('dict0:', dict0) dict1 = dict({'three': 3, 'four': 4}) # 传一个字典 print('dict1:', dict1) dict2 = dict(five=5, six=6) # 传关键字 print('dict2:', dict2) dict3 = dict([('seven', 7), ('eight', 8)]) # 传一个包含一个或多个元祖的列表 print('dict3:', dict3) dict5 = dict(zip(['eleven', 'twelve'], [11, 12])) # 传一个zip()函数 print('dict5:', dict5)
结果:
dict0: {} dict1: {'four': 4, 'three': 3} dict2: {'five': 5, 'six': 6} dict3: {'seven': 7, 'eight': 8} dict5: {'twelve': 12, 'eleven': 11}
数据类型的转换:
将 s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)] 变成 {'yellow': [1, 3], 'blue': [2, 4], 'red': [1]}
比较笨的方法是先定义一个空字典,
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)] d = {} for k,v in s: d.setdefault(k, []).append(v) print(dict(d))
colliections中给我提供了好的api
from collections import defaultdict s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)] d = defaultdict(list)#zhe个参数可以变成int,set(去重) for k,v in s: d[k].append(v) print(dict(d))
数据结构转换例题
范例一:
题目要求:
把这种数据格式变量list,转换成变量dict的这种格式
list=[{'url': '/orders/', 'code': 'list', 'pk': 2}, {'url': '/users/', 'code': 'list', 'pk': 1}, {'url': '/orders/add/', 'code': 'add', 'pk': 1}, {'url': '/orders/delete/(\\d+)', 'code': 'delete', 'pk': 1}, {'url': '/orders/edit/(\\d+)', 'code': 'edit', 'pk': 1}]
dict = { 2: { "urls": ["/orders/", ], "codes": ["list", ] }, }
方法:
dict={ } #首先定义一个字典 for i in list: if i["pk"] in dict.keys(): #判断变量在不在dict中 dict[i["pk"]]["urls"].append(i["url"]) dict[i["pk"]]["codes"].append(i["code"]) else: dict[i["pk"]]={"urls":[i["url"],], "codes":[i["code"]]} print(dict)
结果:
{2: {'urls': ['/orders/'], 'codes': ['list']}, 1: {'urls': ['/users/', '/orders/add/', '/orders/delete/(\\d+)', '/orders/edit/(\\d+)'], 'codes': ['list', 'add', 'delete', 'edit']}}