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})
Как я могу это сделать? Я не знаю, должен ли я взять кортеж, чтобы отредактировать его или выяснить индекс кортежа?
Любая помощь?
Ответы
Ответ 1
Это очень странный способ организовать вещи. Если вы храните в словаре, это легко:
# 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
Этот код для обновления словаря counts является общим "шаблоном" в 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
, вызывая класс, передавая его в любом итерабельном; он создает словарь, где ключи являются значениями из итерируемого, а значения - количеством того, сколько раз ключ появился в истребителе. Приведенный выше пример будет следующим:
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()]
Ответ 2
Использование работы по умолчанию, но так же:
urls[url] = urls.get(url, 0) + 1
используя .get
, вы можете получить возврат по умолчанию, если он не существует. По умолчанию это None, но в том случае, когда я отправил вас, это будет 0.
Ответ 3
Используйте defaultdict:
from collections import defaultdict
urls = defaultdict(int)
for url in list_of_urls:
urls[url] += 1
Ответ 4
это всегда отлично работает для меня...
for url in list_of_urls:
urls.setdefault(url,0)
urls[url]+=1
Ответ 5
Сделать это именно так? Вы можете использовать структуру for... else
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)
Несколько вещей, которые следует отметить в этом втором примере:
- посмотрите, как использование dict для
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
Ответ 6
За исключением первого раза, каждый раз, когда отображается слово, проверка выполнения 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