【问题标题】:How do I create a dict of {str, [list of str]} by looping over a list of str?如何通过循环遍历 str 列表来创建 {str, [list of str]} 的字典?
【发布时间】:2021-03-19 08:16:07
【问题描述】:

在课程中需要餐厅推荐项目的帮助。

我有一个字符串/值列表,我想通过循环创建一个 {str, list of str} 的字典。这是字符串/值的列表:

contents_list_2 = ['Georgie Porgie', 87, '$$$', 'Canadian,Pub Food', 'Queen St. Cafe', 82, '$', 'Malaysian,Thai', 'Dumplings R Us', 71, '$', 'Chinese', 'Mexican Grill', 85, '$$', 'Mexican', 'Deep Fried Everything', 52, '$', 'Pub Food']

我正在尝试创建一个使用 $ 作为键并使用餐厅名称作为值的字典。例如:

{'$': ['Queen St. Cafe', 'Dumplings R Us', 'Deep Fried Everything'],
 '$$': ['Mexican Grill'],
 '$$$': ['Georgie Porgie'],
 '$$$$': []}

我尝试过使用 zip() 函数,但它没有捕获所有餐厅值:

price_to_name = dict(zip(contents_list_2[2::4], contents_list_2[0::4]))
print(price_to_name)
>>> {'$$$': 'Georgie Porgie', '$': 'Deep Fried Everything', '$$': 'Mexican Grill'}

我认为挑战来自为每个键添加一个值列表...我尝试了各种方法,但成功有限。任何帮助将不胜感激!

【问题讨论】:

    标签: python list loops dictionary


    【解决方案1】:

    由于您的数据以 4 为一组,因此最简单的解决方案可能就是循环它:

    from collections import defaultdict
    
    contents_list_2 = ['Georgie Porgie', 87, '$$$', 'Canadian,Pub Food', 'Queen St. Cafe', 82, '$', 'Malaysian,Thai', 'Dumplings R Us', 71, '$', 'Chinese', 'Mexican Grill', 85, '$$', 'Mexican', 'Deep Fried Everything', 52, '$', 'Pub Food']
    price_to_name = defaultdict(list)
    for i in range(0, len(contents_list_2), 4):
        price_to_name[contents_list_2[i + 2]].append(contents_list_2[i])
    
    price_to_name = dict(price_to_name) # get rid of default value
    print(price_to_name)
    

    【讨论】:

    • 或者只是遍历 OP 所做的 zip,并使用它来填充 defaultdict(list)
    【解决方案2】:

    假设字符串以四个为一组,其中第一个是名称,第三个是 $ 评级,您可以这样做

    content = ['Georgie Porgie', 87, '$$$', 'Canadian,Pub Food', 'Queen St. Cafe', 82, '$', 'Malaysian,Thai', 'Dumplings R Us', 71, '$', 'Chinese', 'Mexican Grill', 85, '$$', 'Mexican', 'Deep Fried Everything', 52, '$', 'Pub Food']
    
    ratings = { rating:[N for N,R in zip(content[::4],content[2::4]) if R==rating]
                       for rating in ("$","$$","$$$","$$$$") }
    
    print(ratings)
    
    {'$': ['Queen St. Cafe', 'Dumplings R Us', 'Deep Fried Everything'],
     '$$': ['Mexican Grill'],
     '$$$': ['Georgie Porgie'],
     '$$$$': []}
    

    【讨论】:

      【解决方案3】:

      A collections.defaultdict(list) 是这里的解决方案。您只需要显式循环您的 zip-ed 数据和 append 而不是分配:

      from collections import defaultdict  # At top of file
      
      price_to_name = defaultdict(list)
      for price, name in zip(contents_list_2[2::4], contents_list_2[::4]):
          price_to_name[price].append(name)
      

      这使工作O(n)(每个切片O(n),另一个O(n)循环遍历它们,平均情况/摊销O(1)分别用于查找和append,总体上仍然是O(n) )。

      如果names 可能重复,并且名称的顺序无关紧要(和/或成员资格测试效率很重要),请将list 更改为set 并将append 更改为add

      从技术上讲,您可以使用常规的 dict 来执行此操作,然后改为使用 price_to_name.setdefault(price, []).append(name),但这会不必要地一遍又一遍地创建一个空的 list。成员资格测试或try/except KeyError 也可以,但collections.defaultdict 只是最简单、最快和最明显的解决方案。

      【讨论】:

      • 谢谢。当我添加 print(price_to_names) 时,我得到的输出是:defaultdict(<class 'list'>, {'$$$': ['Georgie Porgie'], '$': ['Queen St. Cafe', 'Dumplings R Us', 'Deep Fried Everything'], '$$': ['Mexican Grill']})。为什么它有额外的 "defaultdict(...etc)" ?
      • @YogeshRiyat:因为它是不同的类类型,而不是普通的dict。如果你想让它在填充后成为一个普通的dict(因此后续访问不会使用新的list自动激活丢失的键),你可以这样做:price_to_name = dict(price_to_name)在循环完成后初始化一个普通的@987654348 @ 与 defaultdict 的当前状态。通常,您不会打印原始对象,除非出于调试目的,因此是否为 defaultdict 更多的是您是否希望将来自动激活。
      • 我现在正在尝试创建 food_to_names。 for i in contents_list_2[3::4]: # Take , out of cuisine element contents_list_2[3::4] = [i.split(',') if ',' in i in contents_list_2[3::4] else i for i in contents_list_2[3::4]] 但我现在收到默认字典错误,因为第三个元素现在是一个列表。有什么想法吗?
      • 我试图在“第 2 部分”下的原始帖子中更清楚地说明这一点
      • @YogeshRiyat:当您有一个新问题与原始问题不太相似时,请针对该特定问题提出一个新问题。您在事后几天添加新问题,从而使您的问题过于宽泛,并使好的答案无效。