Python Set Comprehension 嵌套在 Dict Comprehension 中
Python Set Comprehension Nested in Dict Comprehension
我有一个元组列表,其中每个 tuple
包含一个 string
和一个以下形式的数字:
[(string_1, num_a), (string_2, num_b), ...]
字符串不唯一,数字也不唯一,例如(string_1 , num_m)
或 (string_9 , num_b)
可能存在于列表中。
我正在尝试创建一个以该字符串为键并以该字符串出现的所有数字为值的字典:
dict = {string_1: {num_a, num_m}, string_2: {num_b}, ...}
我已经通过以下带有嵌套集理解的字典理解成功地完成了这项工作:
#st_id_list = [(string_1, num_a), ...]
#st_dict = {string_1: {num_a, num_m}, ...}
st_dict = {
st[0]: set(
st_[1]
for st_ in st_id_list
if st_[0] == st[0]
)
for st in st_id_list
}
只有一个问题:st_id_list
有 18,000 个条目。对于 500 个元组的列表,这段代码用不到 10 秒的时间 运行,但是对于完整的 18,000 个元组,运行 的时间超过 12 分钟。我不得不认为这是因为我在 dict comprehension 中嵌套了一个 set comprehension。
有没有办法避免这种情况,或者更聪明的方法?
你有一个双循环,所以你需要 O(N**2) 时间来生成你的字典。对于 500 件物品,需要执行 250.000 步,对于 18k 件物品,需要完成 324 百万 步。
这里是一个 O(N) 循环,因此对于较小的数据集,500 步,对于较大的数据集,18.000 步:
st_dict = {}
for st, id in st_id_list:
st_dict.setdefault(st, set()).add(id)
这使用 dict.setdefault()
method 来确保对于给定的键(您的字符串值),如果缺少该键,则至少有一个空集可用,然后添加当前的 id
值到那个集合。
你可以用 collections.defaultdict()
object:
做同样的事情
from collections import defaultdict
st_dict = defaultdict(set)
for st, id in st_id_list:
st_dict[st].add(id)
defaultdict()
使用传入的工厂设置缺失键的默认值。
defaultdict
方法的缺点是对象 继续 在循环后为丢失的键生成默认值,这可以隐藏应用程序错误。使用 st_dict.default_factory = None
明确禁用工厂以防止出现这种情况。
当你可以像这样在一个循环中做时,你为什么要使用两个循环:
list_1=[('string_1', 'num_a'), ('string_2', 'num_b'),('string_1' , 'num_m'),('string_9' , 'num_b')]
string_num={}
for i in list_1:
if i[0] not in string_num:
string_num[i[0]]={i[1]}
else:
string_num[i[0]].add(i[1])
print(string_num)
输出:
{'string_9': {'num_b'}, 'string_1': {'num_a', 'num_m'}, 'string_2': {'num_b'}}
我有一个元组列表,其中每个 tuple
包含一个 string
和一个以下形式的数字:
[(string_1, num_a), (string_2, num_b), ...]
字符串不唯一,数字也不唯一,例如(string_1 , num_m)
或 (string_9 , num_b)
可能存在于列表中。
我正在尝试创建一个以该字符串为键并以该字符串出现的所有数字为值的字典:
dict = {string_1: {num_a, num_m}, string_2: {num_b}, ...}
我已经通过以下带有嵌套集理解的字典理解成功地完成了这项工作:
#st_id_list = [(string_1, num_a), ...]
#st_dict = {string_1: {num_a, num_m}, ...}
st_dict = {
st[0]: set(
st_[1]
for st_ in st_id_list
if st_[0] == st[0]
)
for st in st_id_list
}
只有一个问题:st_id_list
有 18,000 个条目。对于 500 个元组的列表,这段代码用不到 10 秒的时间 运行,但是对于完整的 18,000 个元组,运行 的时间超过 12 分钟。我不得不认为这是因为我在 dict comprehension 中嵌套了一个 set comprehension。
有没有办法避免这种情况,或者更聪明的方法?
你有一个双循环,所以你需要 O(N**2) 时间来生成你的字典。对于 500 件物品,需要执行 250.000 步,对于 18k 件物品,需要完成 324 百万 步。
这里是一个 O(N) 循环,因此对于较小的数据集,500 步,对于较大的数据集,18.000 步:
st_dict = {}
for st, id in st_id_list:
st_dict.setdefault(st, set()).add(id)
这使用 dict.setdefault()
method 来确保对于给定的键(您的字符串值),如果缺少该键,则至少有一个空集可用,然后添加当前的 id
值到那个集合。
你可以用 collections.defaultdict()
object:
from collections import defaultdict
st_dict = defaultdict(set)
for st, id in st_id_list:
st_dict[st].add(id)
defaultdict()
使用传入的工厂设置缺失键的默认值。
defaultdict
方法的缺点是对象 继续 在循环后为丢失的键生成默认值,这可以隐藏应用程序错误。使用 st_dict.default_factory = None
明确禁用工厂以防止出现这种情况。
当你可以像这样在一个循环中做时,你为什么要使用两个循环:
list_1=[('string_1', 'num_a'), ('string_2', 'num_b'),('string_1' , 'num_m'),('string_9' , 'num_b')]
string_num={}
for i in list_1:
if i[0] not in string_num:
string_num[i[0]]={i[1]}
else:
string_num[i[0]].add(i[1])
print(string_num)
输出:
{'string_9': {'num_b'}, 'string_1': {'num_a', 'num_m'}, 'string_2': {'num_b'}}