【问题标题】:Python Set Comprehension Nested in Dict ComprehensionPython Set Comprehension 嵌套在 Dict Comprehension 中
【发布时间】:2018-04-26 16:15:04
【问题描述】:

我有一个元组列表,其中每个 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 个元组的列表,这段 sn-p 代码的运行时间不到 10 秒,但对于 18,000 个元组的完整运行,则需要超过 12 分钟。我不得不认为这是因为我在 dict 理解中嵌套了一个集合理解。

有没有办法避免这种情况,或者更聪明的方法?

【问题讨论】:

    标签: python nested dictionary-comprehension set-comprehension


    【解决方案1】:

    当你可以像这样在一个循环中执行时,为什么要使用两个循环:

    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'}}
    

    【讨论】:

      【解决方案2】:

      你有一个双循环,所以你需要 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 明确禁用工厂以防止这种情况发生。

      【讨论】:

      • 哇,非常有帮助,谢谢!额外的好处:我不知道 dict.setdefault() 并且一直在用其他地方的 if 语句来模拟该功能!再次感谢您!
      猜你喜欢
      • 2022-06-17
      • 1970-01-01
      • 1970-01-01
      • 2016-11-10
      • 2013-09-10
      • 2023-04-09
      • 1970-01-01
      • 2015-11-07
      • 1970-01-01
      相关资源
      最近更新 更多