python | 可变数据类型-列表/字典/集合

 

2.5 列表(list)

2.5.1 索引和切片

列表的索引和切片,用法和字符串的索引和切片一模一样,区别在于,面临二维或多维列表时,会有多重索引和切片,思路就是「一层一层往里剥」。

L = [1, 2, 3, 4, [9, 8, 7, 6]]

len(L)
L[4]
L[4][1]
L[4][::-1]

 

2.5.2 常用方法

2.5.2.1 添加元素

方法 含义 原地操作?
append(x) 将元素x添加至列表尾部
extend(L) 将列表L中所有元素添加至列表尾部
insert(index, x) 在列表指定位置index处添加元素x,该位置后面元素后移一位 新生成
+ 添加元素至列表尾部 新生成
* 拼接字符串 新生成
alist = [1, 2, 3]
blist = [4, 5, 6]
alist.extend(blist)  # blist添加至alist后面,原地操作
alist

alist.append(blist)
alist

# append和+的区别
import time
result = []
start = time.time()  # 返回当前时间
for i in range(10000):  # 创建一个整数列表
    result = result + [i]
print('+添加:', time.time()-start)  # 打印列表长度,并计算耗时

result = []
start = time.time()
for i in range(10000):
    result.append(i)
print('Append:', time.time()-start)

# append和insert区别
import time
a = []
start = time.time()
for i in range(100000):
    a.insert(0, i)
print('Insert:', time.time()-start)  # 新生成

a = []
start = time.time()
for i in range(100000):
    a.append(i)
print('Append:', time.time()-start)  # 原地操作

L = [1, 2, 3, 4, 5, 6]
L*3  # 通过乘实现复制

 

2.5.2.2 删除元素

方法 含义 原地操作?
remove(x) 删除首次出现的指定元素x
pop(index) 删除指定index元素,并返回该元素的值,index默认-1
clear(index) 删除列表中所有元素,保留列表对象
del 删除列表中元素或整个列表 /
赋值 对列表中元素或整个列表进行赋值,也算一种删除

拓展:删除列表重复元素有两种思路:

  • for循环中的i基于内容去遍历,用i in list[:]
  • for循环中的i基于index去遍历,用i in range(len(list)-1, -1, -1)
L = [1, 2, 3, 4, 4, 5, 6]
L.remove(4)  # 原地操作
L

# 删除重复元素法1
x = [3, 4, 5, 5, 6]
for i in x[:]:  # 采用切片的方式
    print(i)
    if i == 5:
        x.remove(i)
print(x)

# 删除重复元素法2
x = [3, 4, 5, 5, 6]
for i in range(len(x)-1, -1, -1):  # 从后向前的顺序
    print(i)
    if x[i] == 5:
        del x[i]
print(x)

L = [2, 3, 4, 5]
L.pop(2)  # 实现两个功能:取出4,把4从原列表删除

L = [2, 3, 4, 5]
L.clear()
L

L = [1, 2, 3, 4, 5]
id(L)
L[0:2] = [6, 6]  # 修改多个元素
L
id(L)

L = [1, 2, 3, 4, 5]
del L[1]  # 删除第一个
L
del L  # 删除整个列表
L

 

2.5.2.3 计算&排序

方法 含义 原地操作?
index(x) 返回列表中第一个值为x元素的下标,若不存在则抛出异常 /
count(x) 返回指定元素x在列表中出现的次数 /
reverse() 对列表所有元素进行逆序
sort(key=,reverse=) 对列表元素进行排序,key指定排序依据,reverse决定升序降序:True降序、False升序

 
需要注意,reverse方法和sort方法,都有对应的排序函数:

函数 含义 原地操作?
reversed(L) 对列表L所有元素进行逆序,返回是一个迭代器,需要list化显示
sorted(list, key=, reverse=) 对列表元素进行排序,key指定排序依据,reverse决定升序降序:True降序、False升序 新生成

且无论是在sort还是sorted排序中,参数key通常采用匿名函数「lambda」。

x = [3, 4, 5, 6]
x.index(5)   # 返回索引,不存在则报错
x.count(10)  # 没有返回0,不会报错
x.reverse()  # 原地逆序
x

x = [2, 3, 1, 5, 8]
x.sort()  # 默认是升序
x
x.sort(reverse=True)  # 降序
x

# 自定义排序,使用匿名函数
aList = [[3, 4], [15], [11, 9, 17, 13], [6, 7, 5]]
aList.sort(key=lambda x: len(x), reverse=True)  # 按长度排序,lambda函数,匿名函数
aList

x = [1, 2, 3, 4, 5]
list(reversed(x))  # 新生成

student = [['john', 'A', 15], ['jane', 'B', 12], ['dave', 'B', 10]]  # 按值进行排序
sorted(student, key=lambda a: a[2], reverse=True)

 

2.5.2.4 类型转换

字符串和列表经常互相转换,具体方法是listjoin:

  • 函数list(str):把字符串转化为列表
  • 方法' '.join(L):把列表转化为字符串
s = 'abcd'
list(s)

x = ['apple', 'peach', 'banana', 'peach', 'pear']
'/'.join(x)

 

2.5.2.5 复制

常见的复制有三种:赋值、浅拷贝、深拷贝,三者在使用和表现上都存在区别。

 

2.5.2.5.1 赋值

赋值操作是复制了引用指针,所以数据一方改变,必然导致另一方变化,原理见下图:

# 实质是复制了引用:一方改变,必然导致另一方变化
L1 = [1, 2, 3, 4]
id(L1)
L2 = L1
L2[0] = 0
L2
id(L2)
L1

 

2.5.2.5.2 浅拷贝

浅拷贝有4种形式,而不同维度的数据,在浅拷贝后数据的变化也不尽相同,需要分开讨论,原理见下图及代码:

  • copy()方法
  • 使用列表生成式
  • 用for循环遍历
  • 切片
# 一维:原来值和浅拷贝值互不影响
L1 = [1, 2, 3, 4]
L2 = L1[:]
L2[0] = 0
L2
L1

# 二维或多维:分两种情况讨论
x = [1, 2, 3, [4, 5, 6]]
y = x[:]
y[0] = 0         # 复杂子对象不改变:原来值和浅拷贝值互不影响
y
x

x = [1, 2, 3, [4, 5, 6]]
y = x[:]
y[3][2] = 10     # 复杂子对象改变:原来值和浅拷贝值互相影响
y
x

 

2.5.2.5.3 深拷贝
  • 深拷贝是完全的拷贝,原来值和深拷贝值互不影响
  • 使用copy模块中的deepcopy()方法生成
import copy

L1 = [1, 2, 3, [4, 5]]
L2 = copy.deepcopy(L1)

L2[0] = 0
L2
L1         # 原来值和深拷贝值互不影响

 

2.5.3 内置函数

函数 含义 是否新生成
len() 返回列表中的元素个数 /
max()、min() 返回列表中的最大、最小元素 /
sum() 对列表元素进行求和运算 /
zip() 将多个列表对应位置的元素组合成元组,返回可迭代的zip对象
enumerate() 枚举列表元素,返回元组迭代器,元组中元素包含列表下标、元素的值
L = [1, 2, 3, 4, 5, 6]
sum(L)

L1 = ['a', 'b', 'c']
L2 = [1, 2, 3]
list(zip(L1, L2))  # 生成的是元组迭代器

# 把下标和值打印出来
L1 = ['a', 'b', 'c']
for i, j in enumerate(L1):
    print(i, j)

 

2.5.4 列表推导式

  • 阅读:先看第一个for,再看第二个for,再看条件判断(if),最后看输出结果(表达式)
  • 格式
    • [表达式 for 变量 in 列表]
    • [表达式 for 变量 in 列表 if 条件]
  • 作用
    • 实现嵌套列表的平铺
    • 过滤不符合条件的元素
    • 使用多个循环实现多序列元素的任意组合
    • 实现矩阵转置
    • 使用函数或复杂表达式
    • 实现向量的运算
# 用for循环实现
L1 = [1, 2, 3, 4, 5]
L3 = []
for i in L1:
    L3.append(i**2)
L3

L1 = [1, 2, 3, 4, 5]
[i**2 for i in L1]   # 列表推导式
squar1 = map(lambda x: x**2, L1)  # 用map函数实现对L1的指定映射
list(squar1)

# 列表推导式,加上判断条件
L1 = [1, 2, 3, 4, 5]
[i**2 for i in L1 if i > 2]
[[i, j] for i in range(10) for j in range(10) if i == j]

L1 = [1, 2, 3, 4]
L2 = [4, 5, 6, 7]
[L1[i]+L2[i] for i in range(len(L1))]


L1 = [1, 2, 3, 4]
L2 = [4, 5, 6, 7]
[L1[i]+L2[j] for i in range(len(L1)) for j in range(len(L2)) if i == j]

 

2.6 字典(dictionary)

2.6.1 创建

字典有三种创建方式:

  • 直接赋值创建
  • dict()函数创建
  • 通过给定键值对创建
# 直接赋值创建
addresbook1 = {"小明": "1521055", "小华": "1872345", "小芳": "1389909"}
addresbook1

# 用dict()函数创建
alist = [1, 2, 3]
blist = ['a', 'b', 'c']
dict(zip(alist, blist))   # 将多个列表对应位置的元素组合成元组,返回可迭代的zip对象

# 通过给定键值对创建
dict(name='小明', age=20)  # 等号前是键,等号后是值

 

2.6.2 读取

读取原理:通过key访问value

方法 含义
[key] 以键作为下标读取元素,若不存在则抛出异常
get(x[,y]) 通过键x访问字典:若x存在返回对应的值;若x不存在返回none;若指定了y则x不存在返回y
keys() 返回键的列表
values() 返回值的列表
items(x) 返回元组组成的列表,每个元组由字典的键和相应值组成
copy() 对字典进行浅复制
clear() 删除字典所有元素,保留空字典
addressbook1 = {"小华": "1872345", "小明": "1521055", "小芳": "1389909"}

addressbook1["小明"]     # 通过key访问value
addresbook1.get('小明')  # 存在key时,返回对应的值
addresbook1.get('小红')  # 不存在key时,返回none
addresbook1.get('小红', 110)  # 不存在key时,返回指定的值
addresbook1.keys()
addresbook1.values()
addresbook1.items()
addresbook1.clear()
addresbook1

 

2.6.3 添加与修改

方法 含义
update() 更新信息:把一个字典的键值对添加到另一字典中去,若存在相同的key,则用后者覆盖
pop() 删除指定key,并返回key对应的值
指定键为字典赋值 若键存在则修改键的值,若键不存在则新增键值对
值为可变数据类型 可进行相应数据类型的操作
addresbook1 = {"小明": "1521055", "小华": "1872345", "小芳": "1389909"}
addresbook1['小红'] = '378598345'  # 指定键为字典赋值
addresbook1

# 更新信息,若第一个字典的key在第二个字典也存在,则值以第二个字典的为准
addresbook1 = {"小明": "1521055", "小华": "1872345", "小芳": "1389909"}
addresbook2 = {"小华": "23462346", "小李": "0346246457"}
addresbook1.update(addresbook2)
addresbook1

# pop用法和作用同列表中pop一样
addresbook1 = {"小明": "1521055", "小华": "1872345", "小芳": "1389909"}
addresbook1.pop('小明')
addresbook1

# 值可以为可变序列
addresbook1 = {"小明": "1521055", "小华": "1872345",
               "小芳": [1389909, 1895436, 2748579]}
addresbook1
addresbook1["小芳"].append(9999999)
addresbook1

 

2.6.4 字典推导式

字典推导式语法类似于列表推导式,可快速生成符合指定条件的字典,只是外面是{ }。

# 生成键为序号,值为字符串的字典
{i: str(i) for i in range(5)}

# 将两个序列关联生成,生成字典
x = ['A', 'B', 'C', 'D']
y = ['a', 'b', 'b', 'd']
{x[i]: y[i] for i in range(len(x))}
{i: j for i, j in zip(x, y)}

# 随机产生1000个字符,统计字符次数
import string  # 导入string模块
import random  # 导入random模块
x = string.ascii_letters + string.digits + string.punctuation  # 生成字符串
y = [random.choice(x) for i in range(1000)]    # 列表推导式
d = dict()
for ch in y:
    d[ch] = d.get(ch, 0) + 1  # 不断统计,更新键的值,之前没有值则计1,有则取出加1
d

scores = {"Zhang San": 45, "Li Si": 78, "Wang Wu": 40, "Zhou Liu": 96,
          "Zhao Qi": 65, "Sun Ba": 90, "Zheng Jiu": 78, "Wu Shi": 99, "Dong Shiyi": 60}
scores.values()

max(scores.values())  # 最高分
min(scores.values())  # 最低分
sum(scores.values())/len(scores)  # 平均分
[name for name, score in scores.items() if score == max(scores.values())]    # 最高分同学
[name for name, score in scores.items() if score > (
    sum(scores.values())/len(scores))]  # 高于平均分同学

 

2.7 集合(set)

集合最大的应用场景,就是「去重」。

2.7.1 创建

集合有两种常见创建方式:

  • 直接赋值创建
  • set(x)函数创建
a = {1, 2, 3, 4}   # 直接赋值创建
a

b = [5, 6, 7, 8]   # set()函数创建
set(b)

 

2.7.2 基本操作

基本操作共有4种:交集(&)、并集(|)、差集(-)、补集(^)。

a = {1, 2, 3, 4}
b = {2, 3}

a & b
a | b
a - b
a ^ b

 

2.7.3 包含关系测试

包含关系测试常用于两集合关系判断,返回布尔值。

方法 含义
x.issubset(y) 判断x是否为y子集
{x}.isdisjoint({y}) 判断x与y是否没有交集
用>或<比较大小 判断是否是子集
a = {1, 2, 3, 4}
b = {2, 3}

b.issubset(a)
b.isdisjoint(a)
a > b
b < a

 

2.7.4 常用函数和方法

方法 含义
add(x) 如果x不在集合中,将x增加到集合
clear() 移除集合中所有元素
copy() 浅拷贝
pop() 随机返回集合中的一个元素,若集合为空则报错
discard(x) 若x在集合中,移除x;若x不存在,不报错
remove(x) 若x在集合中,移除x;若x不存在,报错
x in S 判断x是否是集合S元素
x not in S 判断x是否不是集合S元素
函数 含义
len() 返回集合元素个数
a = {1, 2, 3, 4}
a.add(5)
a

b=a.copy()        # 浅拷贝
b

3 not in b

len(b)
posted @ 2019-12-24 10:10  1k-yang  阅读(1223)  评论(0编辑  收藏  举报