列表,元组,字典,集合

国外的一篇关于列表和元组的不同:

https://www.afternerd.com/blog/difference-between-list-tuple/

极客时间Python教程的整理

列表:[],元组()

相同点:都是有序的,可以存储任意数据类型的集合,

不同点1:列表时动态的,可以随意的添加,删减,或改变元素。其存储空间大于元组

不同点2:元组是静态的,长度大小固定,不可以对元素进行增加,删减或者改变操作。元组相对于列表更加轻量,性能稍优

coding

l = []
l.__sizeof__()
#40
l.append(1)
l.__sizeof__()
#72
l.append(2)
l.__sizeof__()
l.append(3)
#72
l.__sizeof__()
#72
l.append(4)
l.__sizeof__()
#72
l.append(5)
l.__sizeof__()
#104

元组和列表常操作的几个函数

count(item)

index(item)

list.reverse()和list.sort()(元组没有这两个内置的函数)

reversed()和sorted()同样表示对列表/元组进行倒转和排序,但是返回一个倒转后或者排好序的新的列表/元组

列表与元组之间的相互转化

list((1,2,3))
#[1,2,3]
tuple([1,2,3])
#(1,2,3)

列表和元组使用场景:

主要根据列表和元组的特性:mutable和immutable

假如你有一个函数,存储的该地理位置的精度和纬度不变

def get_location():
    ..... 
    return (longitude, latitude)

假如你存储的是某个社交平台用户查看日志的数量

viewer_owner_id_list = [] # 里面的每个元素记录了这个 viewer 一周内看过的所有 owner 的 id
records = queryDB(viewer_id) # 索引数据库,拿到某个 viewer 一周内的日志
for record in records:
    viewer_owner_id_list.append(record.id)

集合(Sets)

basket = {'apple','orange','apple','pear'}
print(basket)
#{'apple','orange','apple','pear'}

判断某个元素是否在集合或者字典中 value/key in Sets/dic

集合可以参与加减运算

'orange' in basket
#False
a = set('abcdedf')
b = set('abcded')
a
#{'a','b','c','d','e','d','f'}
a - b
#{'f'}
a = {x for x in 'abracadabra' if x not in 'abc'}
a
{'r','d'}

元素访问的问题

d = {'name':'jason',"age":20}
#
d['name']
'jason'
d['location']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'location'
###当然也可以通过get(key,default)
d = {'name':'jason','age':20}
d.get('name')
'jason'
d.get('location','null')
'null'

集合不支持索引操作

s = {1, 2, 3}
s[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'set' object does not support indexing

集合和字典也同样增加,删除,更新

d = {'name': 'jason', 'age': 20}
d['gender'] = 'male' # 增加元素对'gender': 'male'
d['dob'] = '1999-02-01' # 增加元素对'dob': '1999-02-01'
d
{'name': 'jason', 'age': 20, 'gender': 'male', 'dob': '1999-02-01'}
d['dob'] = '1998-01-01' # 更新键'dob'对应的值 
d.pop('dob') # 删除键为'dob'的元素对
'1998-01-01'
d
{'name': 'jason', 'age': 20, 'gender': 'male'}

s = {1, 2, 3}
s.add(4) # 增加元素 4 到集合
s
{1, 2, 3, 4}
s.remove(4) # 从集合中删除元素 4
s
{1, 2, 3}

对字典根据键值进行升序或者降序

d = {'b': 1, 'a': 2, 'c': 10}
d_sorted_by_key = sorted(d.items(), key=lambda x: x[0]) # 根据字典键的升序排序
d_sorted_by_value = sorted(d.items(), key=lambda x: x[1]) # 根据字典值的升序排序
d_sorted_by_key
[('a', 2), ('b', 1), ('c', 10)]
d_sorted_by_value
[('b', 1), ('a', 2), ('c', 10)]


###集合
s = {3,4,2,1}
sorted(s)
[1,2,3,4]

字典和集合的性能

一个需求:存储了每件产品的ID,名称和价格。通过产品的ID,我们找出价格

def find_product_price(products,product_id)
    for id,price in products:
        if id == product_id:
            return price
products = [
    (143121312,100),
    (432314553,30),
    (32421912367,150)
]

print("The price of product 43231453 is {}".format(find_product_price(products,432314553))
#输出
The price of product .... is 30

###假设使用字典来存储那些值
products = {
  143121312: 100,
  432314553: 30,
  32421912367: 150
}
print('The price of product 432314553 is {}'.format(products[432314553])) 
//time O(nlogn)
# 输出
The price of product 432314553 is 30
//time O(1)

需求变成:要找出这些商品有多少种不同的价格。

#list version
def find_unique_price_using_list(products):
    unique_price_list = []
    for_, price = products
        if price not in unique_price_list:
            unique_price_list.append(price)
    return len(unique_price_list) 
products = [
    (143121312,100),
    (432314553,30),
    (32421912367,150),
    (937153201,30)
]
print("number of unique is:{}".format(find_unique_price_using_list(products)))
#输出
number of unique price is:3
###时间复杂度:O(n^2)
#set version
def find_unique_price_using_set(products):
    unique_price_set = set()
    for _, price in products:
        unique_price_set.add(price)
    return len(unique_price_set)        

products = [
    (143121312, 100), 
    (432314553, 30),
    (32421912367, 150),
    (937153201, 30)
]
print('number of unique price is: {}'.format(find_unique_price_using_set(products)))

# 输出
number of unique price is: 3
###时间复杂度:O(n)

由于集合是高度优化的哈希表,同时里面的元素不能重复访问,同时其添加和查找O(1)的复杂度,那么总的时间复杂度只有O(n)

初始化含有100000个元素的产品,分别计算使用列表和集合统计产品价格数量的运行时间

import time
id = [x for x in range(0, 100000)]
price = [x for x in range(200000, 300000)]
products = list(zip(id, price))

# 计算列表版本的时间
start_using_list = time.perf_counter()
find_unique_price_using_list(products)
end_using_list = time.perf_counter()
print("time elapse using list: {}".format(end_using_list - start_using_list))
## 输出
time elapse using list: 41.61519479751587

# 计算集合版本的时间
start_using_set = time.perf_counter()
find_unique_price_using_set(products)
end_using_set = time.perf_counter()
print("time elapse using set: {}".format(end_using_set - start_using_set))
# 输出
time elapse using set: 0.008238077163696289

初始化字典的方式,哪种更有效

#Option A
d = {'name': 'jason', 'age': 20}
#Option B
d = dic({'name':'jason','age':20,'gender':'male'})

###第一种更有效,第一种直接通过初始化方式生成,第二种,通过调用函数dic()生成

字典的键可以是一个列表么,下面代码中,字典的初始化是否正确,说出理由

d = {'name': 'jason', ['education']: ['Tsinghua University', 'Stanford University']}

####用列表作为 Key 在这里是不被允许的,因为列表是一个动态变化的数据结构,字典当中的 key 要求是不可变的,原因也很好理解,key 首先是不重复的,如果 Key 是可以变化的话,那么随着 Key 的变化,这里就有可能就会有重复的 Key,那么这就和字典的定义相违背;如果把这里的列表换成之前我们讲过的元组是可以的,因为元组不可变