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.Counter 수 Counter있는 클래스를 제공합니다. 클래스를 호출하여 인스턴스를 만들고 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, 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

두 번째 버전은 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.