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。Pythonが呼び出すint()と、ゼロ値が返されます。したがって、最初にURLを参照するとき、そのカウントはゼロに初期化され、次にカウントに1を追加します。

しかし、カウントでいっぱいのディクショナリも一般的なパターンであるため、Pythonはすぐに使用できるクラスを提供します。クラスを呼び出してイテラブルを渡しcontainers.CounterCounterインスタンスを作成するだけです。キーがイテラブルの値であるディクショナリを構築し、値はキーがイテラブルに出現した回数のカウントです。上記の例は、次のようになります。

from collections import Counter  # available in Python 2.7 and newer

urls_d = Counter(list_of_urls)

あなたが実際に示した方法でそれを行う必要がある場合、最も簡単で最速の方法は、これらの3つの例のいずれかを使用してから、必要なものをビルドすることです。

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、存在しない場合にデフォルトの戻り値を取得できます。デフォルトではNoneですが、私が送信した場合は0になります。


12
実際、私はこれが最良の答えだと思います。与えられた辞書にとらわれないので、これは大きなボーナスです。
Bouncner 2013

これは素晴らしいクリーンなソリューションです。
Dylan Hogg 2017年

1
これが答えになるはずです。効率的で、清潔で、要領を得ています!stackoverflowにより、コミュニティが質問の投稿者とともに回答を決定できるようになることを願っています。
mowienay 2017

キーはNoneです^^またはウェル... ...いくつかのより多くのステップを必要とする場合は、本当にこの答えのように、単に動作しない
セドリック


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)

2番目の例で注意すべき点がいくつかあります。

  • dictを使用すると、1つのシングルをテストするときにリストurls全体を調べる必要がなくなります。このアプローチはより速くなります。urlsurl
  • dict( )中括弧の代わりに使用すると、コードが短くなります
  • 使用してlist_of_urlsurlsおよびurl変数名を解析するコードは非常に困難にするとして。それは、次のような明確な何かを、見つけることが良いでしょうurls_to_visiturls_already_visitedcurrent_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

2番目のバージョンは、後で辞書をリストとして変換できるので、優れています。
ナティム2009年

3

初めての場合を除き、単語が表示されるたびにifステートメントのテストが失敗します。多数の単語を数える場合、多くの場合、複数回出現します。値の初期化が1回だけ発生し、その値の拡張が何度も発生する状況では、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.