Python: список dict, если существует, увеличьте значение dict, если не добавляйте новый dict
Я хотел бы сделать что-то подобное.
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})
Как я могу это сделать ? Я не знаю, должен ли я взять кортеж, чтобы отредактировать его или выяснить кортеж indice?
помочь ?
6 ответов:
это очень странный способ организации вещей. Если вы храните в словаре, это легко:
# 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. Это настолько распространено, что существует специальная структура данных,
defaultdict
, созданный только для того, чтобы сделать это еще проще: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
если вы получаете доступ к
defaultdict
С помощью ключа, а ключ еще не находится вdefaultdict
, ключ автоматически добавляется со значением по умолчанию. Элементdefaultdict
принимает вызываемый объект, который вы передали, и вызывает его, чтобы получить значение по умолчанию. В этом случае, мы прошли в классint
; когда Python называетint()
она возвращает нулевое значение. Таким образом, при первой ссылке на URL-адрес его счетчик инициализируется до нуля, а затем добавляется один к счетчику.но словарь, полный подсчетов, также является общим шаблоном, поэтому Python предоставляет готовый к использованию класс:
containers.Counter
вы просто создатьCounter
экземпляр путем вызова класса, передавая в любой итерационный; это создает словарь, в котором ключи являются значениями из iterable, а значения-это количество раз, когда ключ появился в iterable. Приведенный выше пример затем становится:from collections import Counter # available in Python 2.7 and newer urls_d = Counter(list_of_urls)
Если вам действительно нужно сделать это так, как вы показали, самый простой и быстрый способ-использовать любой из этих трех примеров, а затем построить тот, который вам нужен.
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 или новее, вы можете делать это один-лайнер:
from collections import Counter urls = [{"url": key, "nbr": value} for key, value in Counter(list_of_urls).items()]
использование по умолчанию работает, но так же:
urls[url] = urls.get(url, 0) + 1
используя
.get
, вы можете получить возврат по умолчанию, если он не существует. По умолчанию это None, но в случае, если я отправил вас, это будет 0.
использовать defaultdict:
from collections import defaultdict urls = defaultdict(int) for url in list_of_urls: urls[url] += 1
чтобы сделать это именно по-вашему? Вы могли бы использовать для...еще структура
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-адреса в виде списка? Если вы отсортируете его как dict, индексированный строкой url, например, это будет путь чище:
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
устраняет необходимость прохождения через весьurls
список при тестировании одного одинurl
. Такой подход будет быстрее.- используя
dict( )
вместо фигурных скобок делает ваш код короче- используя
list_of_urls
,urls
иurl
как имена переменных сделать код довольно трудно разобрать. Лучше найти что-то более ясное, напримерurls_to_visit
,urls_already_visited
иcurrent_url
. Я знаю, это дольше. Но это яснее.и конечно, я предполагаю, что
dict(url='http://www.google.fr', nbr=1)
упрощение ваши собственные структуры данных, потому что в противном случаеurls
может быть просто:urls = {'http://www.google.fr':1} for url in list_of_urls: if url in urls: urls[url] += 1 else: urls[url] = 1
который может получить очень элегантный с defaultdict позиция:
urls = collections.defaultdict(int) for url in list_of_urls: urls[url] += 1
за исключением первого раза, каждый раз, когда слово видно тест оператора if терпит неудачу. Если вы считаете большое количество слов, многие из них, вероятно, возникнут несколько раз. В ситуации, когда инициализация значения происходит только один раз, а увеличение этого значения будет происходить много раз, дешевле использовать оператор try:
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