比较两个字典列表中值的 Pythonic 方法

Pythonic Way to Compare Values in Two Lists of Dictionaries

我是 Python 的新手,在 Python 期间我仍在努力摆脱 C++ 编码技术,所以如果这是一个微不足道的问题,请原谅我。我似乎找不到最 Pythonic 的方法来做到这一点。

我有两个听写列表。两个列表中的单个字典可能包含嵌套的字典。 (如果你好奇的话,它实际上是一些 Yelp 数据。)第一个字典列表包含这样的条目:

{business_id': 'JwUE5GmEO-sH1FuwJgKBlQ',
 'categories': ['Restaurants'],
 'type': 'business'
 ...}

第二个字典列表包含如下条目:

{'business_id': 'vcNAWiLM4dR7D2nwwJ7nCA',
 'date': '2010-03-22',
 'review_id': 'RF6UnRTtG7tWMcrO2GEoAg',
 'stars': 2,
 'text': "This is a basic review",
 ...}

我想做的是提取第二个列表中与第一个列表中的特定类别匹配的所有条目。例如,如果我对餐馆感兴趣,我只想要第二个列表中的全部内容,其中 business_id 与第一个列表中的 business_id 匹配并且单词 Restaurants 出现在列表中categories.

的值

如果我将这两个列表作为 SQL 中的表,我会在 business_id 属性上进行连接,然后只是一个简单的过滤器来获取我想要的行(其中 Restaurants IN categories,或类似的东西)。

这两个列表非常大,所以我 运行 关注效率和内存 space 问题。在我将所有这些都存入 SQL 数据库之前,有人可以给我一些指示吗?我已经弄乱了 Pandas 一些,所以我在这方面的经验确实有限。我在合并过程中遇到了问题。

假设您的列表名为 l1l2:

来自 l1 的所有元素:

[each for each in l1]

l1 中属于 Restaurant 类别的所有元素:

[each for each in l1
      if 'Restaurants' in each['categories']]

来自 l2 且匹配 id 且来自 l1 且属于 Restaurant 类别的元素的所有元素:

[x for each in l1 for x in l2 
   if 'Restaurants' in each['categories']
   and x['business_id'] == each['business_id'] ]

让我们定义字典示例列表:

first = [
        {'business_id':100, 'categories':['Restaurants']},
        {'business_id':101, 'categories':['Printer']},
        {'business_id':102, 'categories':['Restaurants']},
        ]

second = [
        {'business_id':100, 'stars':5},
        {'business_id':101, 'stars':4},
        {'business_id':102, 'stars':3},
        ]

我们可以分两步提取感兴趣的项目。第一步是收集属于餐厅的商家 ID 列表:

ids = [d['business_id'] for d in first if 'Restaurants' in d['categories']]

第二步是获取那些id对应的dicts:

[d for d in second if d['business_id'] in ids]

这导致:

[{'business_id': 100, 'stars': 5}, {'business_id': 102, 'stars': 3}]

你可以这样做: restaurant_ids = [biz['id'] for biz in list1 if 'Restaurants' in biz['categories']] restaurant_data = [rest for rest in list2 if rest['id'] in restaurant_ids]

然后 restaurant_data 将包含 list2 中包含餐厅数据的所有词典。

这很棘手,我玩得很开心。这就是我要做的:

def match_fields(business, review):
    return business['business_id'] == review['business_id'] and 'Restaurants' in business['categories']

def search_businesses(review):
    # the lambda binds the given review as an argument to match_fields
    return any(lambda business: match_fields(business, review), business_list)

answer = filter(search_businesses, review_list)

这是我找到的最易读的方式。我不太喜欢超过一行的列表推导式,而三行确实推动了它。如果你想让它看起来更简洁,只需使用更短的变量名。为了清楚起见,我喜欢长的。

我定义了一个函数,如果一个条目可以在列表之间匹配,则 returns 为真,第二个函数可以帮助我搜索评论列表。然后我可以说:删除所有在企业列表中没有匹配条目的评论。此模式适用于列表之间的任意检查。

Python 程序员喜欢使用 list comprehensions 作为进行逻辑和设计的一种方式。

列表理解导致更简洁和更紧凑的表达。您认为它很像查询语言是对的。

x = [comparison(a, b) for (a, b) in zip(A, B)] 
x = [comparison(a, b) for (a, b) in itertools.product(A, B)] 
x = [comparison(a, b) for a in A for b in B if test(a, b)]
x = [comparison(a, b) for (a, b) in X for X in Y if test(a, b, X)]

...都是我用的花样

作为仅列表理解方法的变体,使用 set 和生成器理解可能更有效。如果您的第一个列表非常大或者餐厅总数非常大,则尤其如此。

restaurant_ids = set(biz for biz in first if 'Restaurants' in biz['categories'])
restaurant_data = [rest for rest in second if rest['id'] in restaurant_ids]

请注意,暴力列表理解方法是 O(len(first)*len(second)),但它不使用额外的内存存储,而这种方法是 O(len(first)+len(second)) 并使用 O(number_of_restaurants) 额外内存用于 set.