Python : List of dict, if exists increment a dict value, if not append a new dict
我想做那样的事。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | list_of_urls = ['http://www.google.fr/', 'http://www.google.fr/', 'http://www.google.cn/', 'http://www.google.com/', 'http://www.google.fr/', 'http://www.google.fr/', 'http://www.google.fr/', 'http://www.google.com/', 'http://www.google.fr/', 'http://www.google.com/', 'http://www.google.cn/'] urls = [{'url': 'http://www.google.fr/', 'nbr': 1}] for url in list_of_urls: if url in [f['url'] for f in urls]: urls[??]['nbr'] += 1 else: urls.append({'url': url, 'nbr': 1}) |
我该怎么办?我不知道是应该用元组来编辑它,还是计算出元组索引?
有什么帮助吗?
这是一种非常奇怪的组织方式。如果您存储在字典中,这很容易:
1 2 3 4 5 6 7 8 | # This example should work in any version of Python. # urls_d will contain URL keys, with counts as values, like: {'http://www.google.fr/' : 1 } urls_d = {} for url in list_of_urls: if not url in urls_d: urls_d[url] = 1 else: urls_d[url] += 1 |
更新计数字典的代码是Python中常见的"模式"。这是很常见的一种特殊的数据结构,即
1 2 3 4 5 | from collections import defaultdict # available in Python 2.5 and newer urls_d = defaultdict(int) for url in list_of_urls: urls_d[url] += 1 |
如果您使用密钥访问
但是一个充满计数的字典也是一种常见的模式,所以python提供了一个随时可用的类:
1 2 3 | from collections import Counter # available in Python 2.7 and newer urls_d = Counter(list_of_urls) |
如果你真的需要按照你展示的方式来做,最简单和最快的方法就是使用这三个例子中的任何一个,然后构建你需要的一个。
1 2 3 4 5 6 7 | from collections import defaultdict # available in Python 2.5 and newer urls_d = defaultdict(int) for url in list_of_urls: urls_d[url] += 1 urls = [{"url": key,"nbr": value} for key, value in urls_d.items()] |
如果您使用的是python 2.7或更高版本,那么您可以在一行程序中完成它:
1 2 3 | from collections import Counter urls = [{"url": key,"nbr": value} for key, value in Counter(list_of_urls).items()] |
使用默认值是有效的,但是:
1 | urls[url] = urls.get(url, 0) + 1 |
使用
使用默认dict:
1 2 3 4 5 6 | from collections import defaultdict urls = defaultdict(int) for url in list_of_urls: urls[url] += 1 |
这对我来说总是很好的:
1 2 3 | for url in list_of_urls: urls.setdefault(url, 0) urls[url] += 1 |
按你的方式做?您可以使用for…else结构
1 2 3 4 5 6 7 | for url in list_of_urls: for url_dict in urls: if url_dict['url'] == url: url_dict['nbr'] += 1 break else: urls.append(dict(url=url, nbr=1)) |
但它很不漂亮。您真的需要将访问过的URL存储为一个列表吗?例如,如果将其排序为按URL字符串编制索引的dict,则会更清晰:
1 2 3 4 5 6 7 | urls = {'http://www.google.fr/': dict(url='http://www.google.fr/', nbr=1)} for url in list_of_urls: if url in urls: urls[url]['nbr'] += 1 else: urls[url] = dict(url=url, nbr=1) |
在第二个例子中需要注意的几点:
- 请参阅如何使用
urls 的dict,在测试单个url 时,不需要浏览整个urls 列表。这种方法会更快。 - 使用
dict( ) 而不是大括号可以缩短代码长度 - 使用
list_of_urls 、urls 和url 作为变量名使得代码很难解析。最好找些更清楚的,如urls_to_visit 、urls_already_visited 和current_url 。我知道,时间更长。但更清楚了。
当然,我假设
1 2 3 4 5 6 7 | urls = {'http://www.google.fr':1} for url in list_of_urls: if url in urls: urls[url] += 1 else: urls[url] = 1 |
它可以通过默认的dict姿态变得非常优雅:
1 2 3 | urls = collections.defaultdict(int) for url in list_of_urls: urls[url] += 1 |
除了第一次,每次看到单词时,if语句的测试都失败。如果你在数大量的单词,很多单词可能会出现多次。如果一个值的初始化只会发生一次,并且该值的增加会发生多次,那么使用try语句会更便宜:
1 2 3 4 5 6 | urls_d = {} for url in list_of_urls: try: urls_d[url] += 1 except KeyError: urls_d[url] = 1 |
您可以阅读以下内容:https://wiki.python.org/moin/pythonspeed/performancetips