手撕Python之散列类型

2024-09-23 21:19:06 浏览数 (2)

1.字典

思考:如果有多个数据,例如:“凯子”,“男”,19,如何快速存储这些数据

多数我们是通过列表进行存储的

li=['凯子','男',19]

在定义完这个列表之后我们如何来找到数据'凯子'呢?

我们可以通过索引

print(li[0])

如果将来数据顺序发生改变的话,还能用索引值进行访问吗

答案是不能的

数据顺序发生变化,每个数据的下标也随之变化,如何保证数据顺序变化前后能使用同一种方法查找数据呢?

那么这里就涉及到了字典

字典的定义

定义:{‘键’:'值',‘键’:'值'}

1.字典的数据,都是以键值对的方式----键和值都要成对出现

2.键值对之间用逗号隔开

字典的定义:

代码语言:javascript复制
d={'name':'凯子','age':19,'sex':'男'}
print(d)
#{'name': '凯子', 'age': 19, 'sex': '男'}
print(type(d))
#<class 'dict'>

获取字典内值的方式:字典[键]

代码语言:javascript复制
#上面已经将字典定义好了,但是我们现在怎么进行拿值的操作呢?

#获取值---字典[键]:
#序列类型是有顺序的,散列类型是没有顺序的
#字典也是没有顺序的,如果想访问值的话,我们是需要通过键进行获取的
print(d['name'])
#凯子

#我们将顺序进行改变的话我们仍然能进行访问

序列类型是有顺序的,散列类型是没有顺序的

字典也是没有顺序的,如果想访问值的话,我们是需要通过键进行获取的

在字典之内不管顺序怎么变我们都能通过键进行访问

字典注意事项

键必须是唯一的

代码语言:javascript复制
#键必须是唯一的
d={'name': '凯子', 'age': 19, 'sex': '男',"name":"小明"}
print(d)
#{'name': '小明', 'age': 19, 'sex': '男'}
#之前定义的凯子就被这个小明给替换掉了

#如果在字典里面出现重复的键,那么前面的键值对会被后面的键值对给替换掉
'''
因为我们之前就说明了
在字典中对数值的访问我们只能通过键
那么现在有两个一样的键,那么我们是不知道访问谁的
所以在字典中键必须是唯一的

如果同时出现一样的键,那么前面的键值对会被后面键值对提坏

如果确实要定义两个名字的话,我们可以在name后面加上数字进行区分
'''

如果在字典里面出现重复的键,那么前面的键值对会被后面的键值对给替换掉

最好的解决方法就是在键后面加上数字进行区分

键值对必须成对出现,不然就会报错

字典中的键,只能是不可以修改的类型(字符串、元组、数字)

所以我们是不能用列表作为键

字典的操作方式---增删改查

1.获取值---字典[键]:获取对应键的值
代码语言:javascript复制
#获取小明这个值
#字典[键]
print(d['name'])
2.修改值---字典[键]=新值
代码语言:javascript复制
d={'name':'凯子','age':19,'sex':'男'}
d['name']="小红"
print(d)
#{'name': '小红', 'age': 19, 'sex': '男'}
3.添加键值对---字典[新键]=新值
代码语言:javascript复制
d['name3']='小兰'
print(d)
#{'name': '小红', 'age': 19, 'sex': '男', 'name3': '小兰'}

字典[键]=新值

对于这个,键存在,那么就是对这个键指向的值进行修改

如果不存在的话,就是新添加一个新的键以及这个键指向的新值

4.获取字典中的值的方式

1.1字典[键]:获取对应键的值

1.2字典.get(键,键不存在的提示)

代码语言:javascript复制
print(d.get('name'))
#小红
print(d.get('age'))
#19

print(d.get('age1'))
#None
'''
这种方式就会进行一个提示,如果我们输入的键是不存在的话
那么就会提示我们None,说明字典里面并没有这个键
'''


#除此之外,我们是可以自己设置这个提示,提醒我们这个键不存在
print(d.get('age1','键不存在'))
#键不存在

我们可以在这个get函数进行键对应值的查找,并且我们还能判断键是否存在

可以对键不存在的信息进行设置

5.setdefault(键,值)---键存在,返回对应的值

键不存在就会将键值对进行添加

代码语言:javascript复制
d={'name':'凯子','age':19,'sex':'男'}
print(d.setdefault('name5','kk'))
print(d)

#{'name': '凯子', 'age': 19, 'sex': '男', 'name5': 'kk'}
#这里的name5就是不存在的键
#通过这种方法我们直接将这个键放到字典中

print(d.setdefault('name5','55'))
print(d)
#{'name': '凯子', 'age': 19, 'sex': '男', 'name5': 'kk'}
#r如果我们输入的键是存在的话,那么我们就不进行额外的操作了

如果我们输入的键是存在的话,那么我们就不进行额外的操作了

如果我们输入的键是不存在的话,那么我们就在这个字典中添加这个键以及这个键对应的值

但是如果存在的话,我们是不进行额外的操作的

我们仅仅只需要进行键对应的值的打印

setdefault返回的一般是键对应的值

字典.setdefault(键,’数据‘)

小回顾:

代码语言:javascript复制
#当前字典里面有三对键值对
#键和值之间的分割符是冒号
#键值对之间的分隔符是逗号
#用花括号将所有的键值对进行包裹
d={'name':"小明",'age':18,'sex':'男'}


#获取小明这个值
#字典[键]
print(d['name'])

#修改值---字典[键]=新值
d['name']="小红"
print(d)


#添加值--字典[新键]=新值
d['name1']="小工"
print(d)

#这个name1这个键是之前没出现过的
#所以编译器会将这个键和其对应的值会作为键值对添加到字典中



print(d.get('name'))
#小红

#如果不存在我们想寻找的键值对的话,那么编译器会通过这个函数将这个键值对添加到字典之中
print(d.setdefault('name5',"kaizi"))

print(d)

print(d.setdefault('name'))
#如果这个键存在的话,那么setdefault就会返回这个键对应的值
6.update()---添加多个键值对

字典.update(字典)

update添加多个键值对的使用方法:

代码语言:javascript复制
#{'name': '小红', 'age': 18, 'sex': '男', 'name1': '小工', 'name5': 'kaizi'}
#在原有的字典中添加键值对
d.update({'name2':"小李",'age2':'15'})
print(d)
'''
{'name': '小红', 'age': 18, 'sex': '男', 'name1': '小工', 'name5': 'kaizi', 'name2': '小李', 'age2': '15'}
'''
#这个就是在update的括号内添加一个字典
7.pop(键)---删除指定的键值对
代码语言:javascript复制
#{'name': '小红', 'age': 18, 'sex': '男', 'name1': '小工', 'name5': 'kaizi'}
#删除小红
d.pop('name')
print(d)
'''
{'age': 18, 'sex': '男', 'name1': '小工', 'name5': 'kaizi', 'name2': '小李', 'age2': '15'}

'''

#在列表中对元素进行删除的时候使用pop我们在括号内不输入元素的索引值
#那么默认就是删除最后一个元素
#但是现在我们这里的字典的话使用删除的方法的时候我们一定要在括号内加上要删除的键值对的键

在列表中对元素进行删除的时候使用pop我们在括号内不输入元素的索引值

那么默认就是删除最后一个元素

但是现在我们这里的字典的话使用删除的方法的时候我们一定要在括号内加上要删除的键值对的键

pop的内容里面必须要有内容,没有内容的话就是会报错的

8.poptiem()---删除最后一个键值对
代码语言:javascript复制
d.popitem()
print(d)
#{'age': 18, 'sex': '男', 'name1': '小工', 'name5': 'kaizi', 'name2': '小李'}
d.popitem()
print(d)
#{'age': 18, 'sex': '男', 'name1': '小工', 'name5': 'kaizi'}

#返回关键字和值构成的元组

print(d.popitem())
#('name5', 'kaizi')
print(d)
#{'age': 18, 'sex': '男', 'name1': '小工'}
print(d.popitem())
#('name1', '小工')

#返回的值就是要删除的键值对组成的元组
代码语言:javascript复制
#返回关键字和值构成的元组

print(d.popitem())
#('name5', 'kaizi')
print(d)
#{'age': 18, 'sex': '男', 'name1': '小工'}
print(d.popitem())
#('name1', '小工')

#返回的值就是要删除的键值对组成的元组
9.values()获取字典中所有的值

字典.values()

代码语言:javascript复制
d={'name':"小明",'age':18,'sex':'男',"name1":"小红"}
print(d.values())
#dict_values(['小明', 18, '男', '小红'])
代码语言:javascript复制
for i in d.values():
    print(i)

'''
小明
18
男
小红

对于这个循环的写法,我们编译器会先执行这个d.values的方法,
print(d.values())
#dict_values(['小明', 18, '男', '小红'])
获取到字典中的值
这些值都被存在一个列表中
然后我们i遍历这个列表打印每一个值
'''

我们将d.values写到for循环的条件中

我们先进行d.values的编译,然后生成了一个列表,这个列表里面存着的就是这个字典里面的数据

然后i进行这个列表的遍历,然后进行数据的打印

10.keys()---获取字典中所有的键
代码语言:javascript复制
d={'name':"小明",'age':18,'sex':'男',"name1":"小红"}
print(d.keys())
#dict_keys(['name', 'age', 'sex', 'name1'])
#同样,获取的键也会存在列表中
#那么我们也可以同样利用for循环遍历这个链表进行键的打印

for i in d.keys():
    print(i)

'''
name
age
sex
name1

'''

将获取的键存在列表中,利用for循环进行遍历列表,打印每一个键

11.items()---获取字典中所有的键值对
代码语言:javascript复制
#利用items就能获取这个字典内的键值对,得到的键值对会被存在列表中
#每一个键值对在列表中存在的元素是元组形式的
d={'name':"小明",'age':18,'sex':'男',"name1":"小红"}
print(d.items())
'''
dict_items([('name', '小明'), ('age', 18), ('sex', '男'), ('name1', '小红')])
'''

#我们从这个存储键值对的列表中进行遍历,打印每一个键值对

for i in d.items():
    print(i)
'''
('name', '小明')
('age', 18)
('sex', '男')
('name1', '小红')
'''

用键:值这个格式将字典内的键值对表示出来

因为我们使用items获取到的键值对是以元组形式存进这个列表的

那么我们随着i的变化就能进行列表中所有键值对的访问,也就是对元组的访问

那么我们是可以通过索引值访问元组内的元素的

这个元组内的元素下标为0就是键,1就是键指向的数据

那么我们就可以利用循环将这个格式进行输出

利用索引值将键值队的格式表现出来:

代码语言:javascript复制
#键值对存在列表中
#对于这个循环来说,i存放的数据是键值对的数据,键值对输出的格式是---键:值
#因为键值对存在列表中,所以我们是可以用下标进行访问的

d={'name':"小明",'age':18,'sex':'男',"name1":"小红"}
print(d.items())
#dict_items([('name', '小明'), ('age', 18), ('sex', '男'), ('name1', '小红')])
for i in d.items():
    #print(i)
    #通过索引的方式将键和值单独的获取
    #键值对在这个列表中存在的形式是元组
    #通过i的变化,我们访问每一个键值对
    #那么我们就可以用i 索引进行元组内元素的访问的操作了
    print(i[0])#访问的是键
    print(i[1])#访问的是值

    print(f'{i[0]}:{i[1]}')
'''
那么我们通过循环就打印出这么个样子
name:小明
age:18
sex:男
name1:小红

和我们预期的是一样的
'''

除了使用索引,我们还能使用拆包的方法

回顾一下什么事拆包

元组可以同时赋值给多个变量,只要变量个数不超过元组长度,变量前面加上* 号则可以将多于元素都接受,并组成一个列表

代码语言:javascript复制
d={'name':"小明",'age':18,'sex':'男',"name1":"小红"}
print(d.items())
#dict_items([('name', '小明'), ('age', 18), ('sex', '男'), ('name1', '小红')])
for i in d.items():
    a,b=i
##    print(a)
##    print(b)
    print(f'{a}:{b}')
'''
随着i的遍历,每次都指向着不同的元组,就是指向不同的键值对
那么所以说i种存在两个值,就是键和键指向的值
那么我们就利用元组的拆包的操作
将键值对这两个值存在我们创建的两个变量中
a就是存储键
b就是存储值了
那么我们利用循环,i遍历整个列表我们将整个列表中的元素都进行打印了
'''
#两种方法都能实现我们想要的效果
'''
name:小明
age:18
sex:男
name1:小红

'''

2.集合

集合的概念以及定义(包括空集合)

集合的定义:{元素1,元素2…….}

代码语言:javascript复制
i={1,5,6}
print(type(i))
#<class 'set'>

那么空集合该怎么进行使用呢?

如果我们光写一个花括号的话,那么这个是不是就能表示空集合呢?

答案是不能的

代码语言:javascript复制
q={}
print(type(q))
#<class 'dict'>

最后打印出来的类型是一个字典

所以说一个空的花括号表示的是字典

其实空集合的创建是set()

代码语言:javascript复制
o=set()
print(type(o))
#<class 'set'>

所以set就是集合的表示方式

创建空集合一定要使用set()

集合的特点

1.集合是和字典是一样的,元素是没有顺序的

所以我们在打印集合的时候打印出来的数据的顺序都是随机的

2.集合内的元素都是唯一的

如果我们在定义集合元素的时候有多个相同的元素的话,那么我们在打印的时候指只会保留一个

代码语言:javascript复制
j={1,2,3,'hu',5,6,1,5}
print(j)

#{1, 2, 3, 5, 6, 'hu'}

所以集合是无序不重复的散列

集合的操作

1.去重:利用集合的特点---元素是唯一的
代码语言:javascript复制
#对列表进行去重的操作
li=[12,56,89,56,16]

#将列表转换为集合的类型
j2=set(li)
print(j2)
#{56, 89, 12, 16}
#然后将集合转换为列表,然后这个列表就完成了去重的操作了
li=list(j2)
print(li)

如果一个列表需要进行去重的话,我们就可以将这个列表转换为集合然后进行去重的操作

2.修改

对于集合的话我们是没有直接的修改的操作的

我们只能先删除再添加

3.添加

#### 3.1 add(元素)---添加元素到集合中

我们说加什么add就加什么,不会做额外的操作

代码语言:javascript复制
#添加操作
j={1,2,3,'hu',5,6,1,5}
j.add("你好啊")
print(j)
#{1, 2, 3, 'hu', 5, 6, '你好啊'}

#### 3.2 upodate(序列/散列)

这个函数会将我们输入的要添加的序列或者是散列给拆分了

代码语言:javascript复制
#添加序列的话
#update(序列/散列)
j.update("你好")
print(j)
#{1, 2, 3, 5, 6, 'hu', '你', '好', '你好啊'}
#可以发现我们后面输入的被拆开了
#将我们输入的序列或者是散列类型的数据拆开放到集合中

括号内是不能够写数字的,会报错,因为括号内只能写序列和散列

4.删除

#### 4.1remove(指定元素)

我们是需要指定值进行操作的

代码语言:javascript复制
j={1,2,3,'hu',5,6,1,5}
j.remove("hu")
print(j)
#{1, 2, 3, 5, 6}
j.remove(5)
print(j)
#{1, 2, 3, 6}

#### 4.2pop()---删除随机元素

之所以删除随机元素,因为数据的位置都是随意变动的

代码语言:javascript复制
#{1, 2, 3, 6}

j.pop()

print(j)
#{2, 3, 6}
5.交集、并集

只有集合里面存在这个概念

#### 5.1交集----- &

取出两个集合中相同的内容

代码语言:javascript复制
a={1,2,3,4}
b={3,4,5,6}
print(a&b)
#{3, 4}

#### 5.2并集----- |

两个集合合并在一起

代码语言:javascript复制
a={1,2,3,4}
b={3,4,5,6}
print(a|b)
#{1, 2, 3, 4, 5, 6}

集合中每个数据都是唯一的

那么出现的两个3和两个4最后都只保留了一个

要遵循集合的规则

至此,我们的数据类型就学完了

运算符的优先级

赋值元素符就是左右两边的内容进行指定的算术运算再将结果赋值给左边的变量

成员运算符

成员运算符有两个:in not in

成员运算符在序列和散列居多

主要是判断某个内容在这一堆是否存在

使用格式:数据 in 序列/散列

判断数据是不是序列/散列的成员

成员运算符的使用

代码语言:javascript复制
#判断字符p是不是python的成员
print('p'in'pyhton')
#True

li=['李四''张三''王二']
if "小明" in li:#判断小明在不在名字列表里面
    print(True)
else:
    print(False)
#False

#判断字符q是否不是python的成员
print('q'not in'pyhton')
#not in 的操作就是和in的操作是相反的
身份运算符

看的是你引用的是不是同一块内存空间的内容

is判断两个内容是不是同一个地址

is not相反

代码语言:javascript复制
a=1
b=a
c=2
print(a is b)#True
#a和b指定同一块空间
print(a is c)#False
#a和c不指向同一块空间

print(f'a:{id(a)}')
print(f'b:{id(b)}')
print(f'c:{id(c)}')
#a:1535758792
#b:1535758792
#c:1535758808


#可见, 我们通过id()这个函数我们就能看的出a和b二档地址与c是不同的

#is判断两个内容是不是同一个地址
#is  not相反

使用id()能查看数据的地址

可变复制---copy()

在进行重要数据的赋值之前

我们需要对这个数据进行一个拷贝复制,因为这个数据一但被修改了就不能回复了

所以我们需要提前将这个数据进行复制一下

对于可以修改的数据类型,之前的数据就没有了

且不能恢复

如果想保留修改之前的数据

我们需要提前备份一份数据

我们需要使用到copy()函数

copy()函数的使用方式:

代码语言:javascript复制
li=[1,2,3,4,5]
print(id(li))#72456872
li1=li.copy()
print(li1)
#[1, 2, 3, 4, 5]
print(id(li1))#72456840

我们使用copy去备份数据的时候,copy会去额外申请一个空间去放这个备份的数据

备份类型直接对于只能修改的类型

列表、字典、集合

如果我们是想通过赋值来达到备份的效果,这个是不可能的

因为我们赋值出来的对象与原先的对象都指向着同一块空间的

那么我们将原先对象进行改变,那么备份的对象也会被改变,因为都指向同一块空间

所以我们需要copy()来专门进行备份的操作

通过copy会额外申请一块空间

3.回顾

1.数值类型

整型 int 整数 不可以修改的

浮点型 float 带小数点的数字 不可以修改的

布尔型 bool True(真1)、False(假0) 不可以修改的

2.序列类型(索引、切片)

字符串 str 用引号括起来的内容 不可以修改的(存在修改方法,但是会生成新的字符串)

列表 list [元素1,元素2] 可以修改

元组 tuple (元素1,元素2) 不可以修改的

3.散列类型

字典 dict {键:值,键:值} 可以修改

集合 set {元素1,元素2} 可以修改

题目

1.用户登录

如果用户名存在就输入密码,当密码正确的时候就显示登录成功并且退出程序

如果用户名不存在则提示用户注册

判断用户是否存在

存在---输入密码

不存在---提示用户注册

代码语言:javascript复制
students =[
{'name':'张三','password':123},
{'name':'王五','password':888},
{'name':'赵六','password':456}
]
name=input("请输入用户名:")
for i in students:
    #i存在的是用户的信息字典
    if name==i['name']:
        #对输入的用户名进行判断
        for n in range(1,4):
            #循环3次进行输入密码的操作,如果输入正确直接跳出循环
            pwd=eval(input("请输入密码:"))
            if pwd==i['password']:
                print('登录成功')
                exit()
                #break#只能退出当前所在的循环,就是跳出了里面的循环,还是处于外部循环
            else:
                print(f'密码错误,还剩{3-n}次机会')
    #if name==i['name'] and pwd==i['password'] :
        break
else:#循环正常结束执行,即没有break语句
    print("用户名不存在")

#对于这个程序的话,我们 不管输入什么最后都会打印这个用户名不存在
#我们内循环里面的break仅仅只够我们跳出内部循环
#但是没有跳出外部循环,这就是为什么会打印else的那句话
#那么我们就在外部循环加上一个判断语句,如果条件成立就直接跳出
#那么就不会进行这个循环后面的代码了

#总结,就是break只能退出当前所在的循环,所以在外边循环中我们需要再写一个break跳出外部循环

#对于后面的这个else语句来说
#循环正常结束执行,即没有break语句


#但是我们在内循环break的位置加一个exit()
#我们直接退出这个程序,那么就没有后面else的事了

#如果后面有代码的话,这个exit()影响到了后面代码的执行的话
#那么我们就使用break来跳出
#两个break
代码语言:javascript复制
students =[
{'name':'张三','password':123},
{'name':'王五','password':888},
{'name':'赵六','password':456}
]
name=input("请输入用户名:")
for i in students:
    #print(i)
    if name in i.values():
        #获取当前字典内的值
        #我们在这里需要用到字典相关的函数--values去获取字典内的值
        #查看当前遍历到的字典有没有我们输入的name
        #print("存在")
        for n in range(3):
            pws=int(input("请输入密码:"))
            if pws==i['password']:
                print("登录成功")
                exit()
            else:
                print(f"密码错误,还剩{3-n}次机会")


else:#循环正常结束才会执行
    print("用户名不存在")
#在这个代码里面只有一个循环
#那么我们在break之后我们就不会触发这个else了,我们直接跳出循环了
#我们这里的break跳出循环是非正常循环的
2.数字重复统计:
代码语言:javascript复制
'''
数字重复统计:
(1)随机生成1000个整数  
import.random
random.randint
(2)数字的范围[20,100]
(3)升序输出所有不同的数字及每个数字重复的次数
'''
import random
li=[]#创建一个空列表
for i in range(1000):
    num=random.randint(20,100)
    print(num)
    li.append(num)#我们将每次循环产生的数添加到这个列表中

print(li)

#升序输出所有不同的数字---去重(转换为集合),排序(sort)
li1=list(set(li))
#先转换为集合再转换为列表,我们就达到了去重的效果
print(li1)
li1.sort()#默认是从小到大,升序的
print(li1)

#每个数字重复的次数---统计数字出现的次数(序列.count(数据))
for i in li1:#遍历去重的列表
    #进行统计,对没有机芯工去重的列表进行统计
    x=li.count(i)
    print(f'{i}出现了{x}次')

#我们所有的数字已经在li1里面了,而且没有重复的
#那么我们将这个列表作为外循环的条件进行遍历
#然后我们在li这个链表即兴每次遍历的数字的出现次数的计算


#我们需要将元素存储起来
#那么存放多个元素的有什么呢?
#列表、元组(不可修改)、字典(键值对)、集合
#那么最后只有列表和集合方便
#这个题的要求是还要统计重复数字的次数而且保存重复的数字
#那么我们直接将字典排除了
#因为字典是去重的
#那么最后我们就使用列表来对这些数字进行存储

我们在最后统计每个数字出现的次数

我们将每个数字进行去重

然后针对每个数字进行计数

通过这里的代码就会缩短时间

如果我们是对1000个数字一个一个进行遍历的话会很慢的

我们第一步直接将出现的数字缩水显现出来

然后我们再在原先的列表中进行遍历计算这个数字出现的次数

0 人点赞