一个没有重复项的集合
集合(set)每个值最多出现一次,也没有位置:{"AAPL", "MSFT", "GOOG"}。添加已存在的值不会有任何变化。set(items) 能把任何可迭代对象变成集合,这是去重最快的方法,此时 len 统计的是不同值的个数。集合没有顺序,所以不能按索引访问,打印时看到的顺序也不可依赖。空集合要写成 set():{} 是空字典。
symbols = ["AAPL", "MSFT", "AAPL", "GOOG", "MSFT"]
# set() removes repeats
unique = set(symbols)
print(len(symbols), len(unique)) # 5 3
# Adding something already there changes nothing
unique.add("AAPL")
unique.add("TSLA")
print(len(unique)) # 4
# {} is a dict; an empty set is set()
print(type({}), type(set())) # <class 'dict'> <class 'set'>快速的成员检测
x in some_set 几乎瞬间就能得到答案,即使有数百万个值,因为集合通过哈希定位,而不是逐个扫描。对列表做同样的检测要逐个检查元素,列表越大越慢。所以如果要对同一个集合反复使用 in(例如把每个收到的订单与禁止交易代码列表对比),就把它一次性转换成集合。集合的成员必须可哈希,和字典的键一样。
# Membership: a set is the fast structure for "is it in there?"
banned = {"GME", "AMC", "BBBY"}
orders = ["AAPL", "GME", "MSFT", "AMC"]
allowed = [symbol for symbol in orders if symbol not in banned]
print(allowed) # ['AAPL', 'MSFT']
# Sets only keep hashable values
try:
{["AAPL"]}
except TypeError as error:
print("not hashable:", error)集合运算
集合可以像数学课上那样组合。a | b 是并集(在任一个中),a & b 是交集(同时在两者中),a - b 是差集(在 a 中但不在 b 中),a ^ b 是对称差(只在其中一个中)。每种运算也有对应的方法,如 a.union(b),它接受任何可迭代对象。它们都返回新集合,不改动 a 和 b。这正是比较两个代码池或两份持仓清单所需要的。
# Comparing yesterday's and today's universe
yesterday = {"AAPL", "MSFT", "GOOG", "IBM"}
today = {"AAPL", "MSFT", "TSLA"}
print(sorted(yesterday | today)) # ['AAPL', 'GOOG', 'IBM', 'MSFT', 'TSLA']
print(sorted(yesterday & today)) # ['AAPL', 'MSFT']
print(sorted(today - yesterday)) # ['TSLA'] (new listings)
print(sorted(yesterday - today)) # ['GOOG', 'IBM'] (dropped)
print(sorted(yesterday ^ today)) # ['GOOG', 'IBM', 'TSLA']修改集合并保持顺序
add(x) 插入一个值,update(items) 插入多个,discard(x) 在值存在时删除它(不报错),remove(x) 同样删除,但值不存在时会引发 KeyError。集合不记顺序,所以顺序重要时就要用列表:sorted(some_set) 得到已排序的列表;要在去重的同时保持首次出现的顺序,就遍历这些值,并用一个集合记住已见过的值(seen)。因为是集合,这个检查很快。
# Remove repeats and keep the first-seen order
symbols = ["MSFT", "AAPL", "MSFT", "GOOG", "AAPL"]
seen = set()
ordered = []
for symbol in symbols:
if symbol not in seen:
seen.add(symbol)
ordered.append(symbol)
print(ordered) # ['MSFT', 'AAPL', 'GOOG']
# discard is quiet, remove is strict
seen.discard("TSLA")
try:
seen.remove("TSLA")
except KeyError:
print("TSLA was not in the set")集合没有顺序:展示或比较前先排序两个相等的集合打印出来的顺序可能不同,所以绝不要依赖这个顺序。返回或打印集合运算的结果时,用
sorted(...) 包起来得到稳定的列表。实验要求返回排序后的列表,正是出于这个原因。set(items):每个值只保留一个;len(set(items))统计不同值的个数。x in s很快;a | b、a & b、a - b、a ^ b生成新集合。- 集合没有顺序:需要列表时用
sorted(s)。
下一节:读写文本文件,让你的程序在多次运行之间保存数据。
实验:评分内容
- 用
distinct_count统计不同的代码数量25 分 - 用
new_listings找出新出现的代码25 分 - 用
common_symbols找出两个投资组合的共同部分25 分 - 用
dedupe_keep_order去重并保持顺序25 分