二.再次了解字典和集合
我们在第一章对列表和元组深入的了解了一下,这次我们来看看另外两种常用的数据类型:字典(dict)和集合(set) 。
一.基础知识:
字典是一系列由键(key)和值(value)配对组成的元素的集合,只有在3.7以后的版本中字典才被确定为有序的。其长度可变,元素可以任意增减和改变。
集合和字典基本相同,区别就是没有键值的配对,并且是一系列无序的、唯一的元素的集合。
相比于列表和元组,字典的性能更优,特别是对于查找、添加和删除操作,字典都能在常数时间复杂度内完成操作。
二.使用
假设我们由下面几个字典和集合
dic = {'1':"a", '2':'b', 3:'c'} s = {1,'abc',3.0}
可以发现,不论是字典还是集合无论是键还是值,数据类型都可以是混合使用的。
而对于元素访问的问题,字典可以直通过对引键的值来进行索引,如果键不存在,就会抛出异常。
dic[1] Traceback (most recent call last): File "D:/python/happy chicken/123.py", line 5, in <module> dic[1] KeyError: 1
如果是直接这样索引键的值,一定要加上容错的机制,否则程序就崩溃了。还有一种方法是用get()函数,如果键不存在就会返回一个None。
dic.get(1) 'None'
而集合由于是无序的,不支持索引操作。因为集合本质上和列表不同,是一个哈希表。所以可以通过valve in set/dic的方式判定值是否在列表或字典里(字典只能判定key是否在)。
'1' in dic 1 in s
Ture
Ture
当然也包括增删改查的操作
#增 dic[4] = 'd' s.add('abc') #删 dic.pop[3] s.remove(1) s.pop() #改 dic['1']='aaa'
注意的是由于集合是无序的,用pop()函数的话是随机最后一个元素,那就不知道删的是哪个了!一定要谨慎使用。
三.性能
我们做一个这样的试验:有一个商品列表,元素是一个元组,里面存了该商品的ID(int)和单价(float),我们试一下检索这件商品的价格
products = [(0,100.0),(1,99.5),(2,50.6),(3,47.7)] def find_product_price(products,product_id): for id,price in products: if id == product_id: return price return None price = find_product_price(products,2) print(price)
假设商品列表里有n个元素,那么查找的过程要遍历整个列表,呢么时间复杂度为O(n)。即使我们先对列表排序后用二分法查找也需要O(logn)的时间复杂度。而列表的排序也要O(nlogn)的时间。
而如果我们用字典的类型存储这些数据,那么查找就会变得很高效。只需O(1)的时间复杂度就可以完成。由于字典内部是一个哈希表,可以通过键的哈希值来找对应的值。
products = {0:100.0, 1:99.5, 2:50.6, 3:47.7} def find_product_price(products,product_id): return products.get(product_id) price = find_product_price(products,2) print(price)
看,操作起来是不是也更简单(这里是为了比较,其实都不用这个函数,直接用get()索引id对应的价格就可以了!)
在来一个难一点的:现在要统计一下这些商品中有多少种价格,我们试一下分别用列表和集合来实现。
products = [(0,100.0),(1,99.5),(2,50.6),(3,47.7),(4,47.7)] def find_unique_price(products): unique_price_list = [] #创建价格列表 for _,price in products: if price not in unique_price_list: unique_price_list.append(price) return len(unique_price_list) print(find_unique_price(products))
这里用了一层for循环嵌套了一个if判断,假设原始的列表有n个元素,最差的情况下需要O(n^2)的时间复杂度。
products = [(0,100.0),(1,99.5),(2,50.6),(3,47.7),(4,47.7)] def find_unique_price(products): uniqur_price_set = set() #创建集合 for _,price in products: uniqur_price_set.add(price) return len(uniqur_price_set) print(find_unique_price(products))
这里用了一个集合,每次循环直接把price加在集合里。而集合是去重的,而添加和查找的操作只需要O(1)的时间复杂度,那么总时间复杂度就只有O(n)。
这里由于元素少不是特别直观我们直接生成一个1,000,000个元素的产品列表演示一下
import time id = [x for x in range(0,1000000)] price = [x for x in range(20000,30000)] products = list(zip(id,price)) start_time = time.perf_counter() find_unique_price(products) end_time = time.perf_counter() print(end_time-start_time)
列表时间:0.6533774739276819
集合时间:0.0012942212969428366
可以看出了只有1000000个数巨量两者的速度就差了这么多,如果使用了不合适的数据结构很容易造成服务器的崩溃。
四.字典和集合的工作原理
上面说过了,字典和集合内部结构都是一个哈希表,对于字典来说,表内存了哈希值(hash),key,value三个元素;而对集合来说就只有单一的元素了。至于在哈希表内是如何存储的,我们以后有时间再分析!