Python : dict 목록, 존재하는 경우 새 dict를 추가하지 않으면 dict 값을 증가시킵니다.


107

그런 식으로하고 싶습니다.

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})

어떻게해야합니까? 튜플을 편집하거나 튜플 인덱스를 알아 내기 위해 튜플을 가져와야하는지 모르겠습니다.

도움이 필요하세요?

답변:


207

그것은 사물을 정리하는 매우 이상한 방법입니다. 사전에 저장했다면 간단합니다.

# 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. 파이썬이 호출 int()하면 0 값을 반환합니다. 따라서 URL을 처음 참조하면 개수가 0으로 초기화 된 다음 개수에 1을 추가합니다.

그러나 카운트로 가득 찬 딕셔너리도 일반적인 패턴이므로 Python은 즉시 사용할 containers.CounterCounter있는 클래스를 제공합니다. 클래스를 호출하여 인스턴스를 만들고 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()]

나는 그것을 django 템플릿으로 보내는 것을 좋아한다. 그래서 나는 할 수있다.`{% for u in urls %} {{u.url}} : {{u.nbr}} {% endfor %}
Natim

3
{% for url, nbr in urls.items %} {{url}} : {{nbr}} {% endfor %}
stefanw 2009

160

기본값을 사용하면 작동하지만 다음과 같이 작동합니다.

urls[url] = urls.get(url, 0) + 1

를 사용 .get하면 존재하지 않는 경우 기본 반환을 얻을 수 있습니다. 기본적으로 없음이지만 내가 보낸 경우에는 0이됩니다.


12
실제로 나는 이것이 최고의 대답이라고 생각합니다. 주어진 사전에 대해 불가지론 적이므로 엄청난 보너스 이모입니다.
Bouncner 2013

이것은 좋은 깨끗한 솔루션입니다.
Dylan Hogg

1
이것이 답이되어야합니다. 효율적이고 깨끗하며 요점! 나는 stackoverflow가 커뮤니티가 질문 포스터와 함께 답을 결정할 수 있기를 바랍니다.
mowienay

키가 None ^^ 아니면 잘 ... 몇 가지 단계가 더 필요합니다 ...
Cedric


17

이것은 항상 나를 위해 잘 작동합니다.

for url in list_of_urls:
    urls.setdefault(url, 0)
    urls[url] += 1

3

정확히 당신의 방식대로하기 위해서? 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을 목록으로 저장해야합니까? 예를 들어 URL 문자열로 색인이 지정된 dict로 정렬하면 훨씬 더 깔끔합니다.

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 for를 사용하면 하나의 단일을 테스트 할 때 urls전체 urls목록 을 살펴볼 필요가 없습니다 url. 이 접근 방식은 더 빠를 것입니다.
  • dict( )중괄호 대신 사용하면 코드가 짧아집니다.
  • 사용 list_of_urls, urlsurl변수 이름은 구문 분석 코드가 매우 어렵게한다. 이 같은 명확한 무언가를 찾기 위해 더 나은 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

두 번째 버전은 dict를 목록으로 변환 할 수 있기 때문에 좋습니다.
Natim 2009

3

처음을 제외하고는 단어를 볼 때마다 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를 읽을 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.