二.再次了解字典和集合

我们在第一章对列表和元组深入的了解了一下,这次我们来看看另外两种常用的数据类型:字典(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三个元素;而对集合来说就只有单一的元素了。至于在哈希表内是如何存储的,我们以后有时间再分析!

原文地址:https://www.cnblogs.com/yinsedeyinse/p/11113498.html