web-dev-qa-db-ja.com

Pythonの辞書の辞書にあるすべてのキーの数を取得する

辞書の辞書はPython 2.7にあります。

各辞書内のキーを含むすべてのキーの数をすばやくカウントする必要があります。

したがって、この例では、すべてのキーの数を6にする必要があります。

dict_test = {'key2': {'key_in3': 'value', 'key_in4': 'value'}, 'key1': {'key_in2': 'value', 'key_in1': 'value'}}

私はforループで各キーを反復処理できることを知っていますが、数千/数百万のキーがあり、これを行うのは効果的ではないので、これを行うより迅速な方法を探しています:

count_the_keys = 0

for key in dict_test.keys():
    for key_inner in dict_test[key].keys():
       count_the_keys += 1

# something like this would be more effective
# of course .keys().keys() doesn't work
print len(dict_test.keys()) * len(dict_test.keys().keys())
37
ivan_bilan

シンプルに保つ

すべての値が辞書であり、それらの値のいずれも辞書であることを確認したくない場合は、次のように簡単です。

len(dict_test) + sum(len(v) for v in dict_test.itervalues())

値を数える前に、実際に値が辞書であることを確認するために、少し改良します。

len(dict_test) + sum(len(v) for v in dict_test.itervalues() if isinstance(v, dict))

そして最後に、次のような任意の深さを行いたい場合:

def sum_keys(d):
    return (0 if not isinstance(d, dict) 
            else len(d) + sum(sum_keys(v) for v in d.itervalues())

print sum_keys({'key2': {'key_in3': 'value', 'key_in4': 'value'}, 
                'key1': {'key_in2': 'value', 
                         'key_in1': dict(a=2)}})
# => 7

この最後のケースでは、再帰的に呼び出される関数を定義します。値dを指定すると、次のいずれかが返されます。

  • 0その値が辞書でない場合。または
  • 辞書内のキーの数、およびすべての子のキーの合計。

高速化

上記は簡潔で理解しやすいアプローチです。ジェネレーターを使用すると、少し速くなります。

def _counter(d):
    # how many keys do we have?
    yield len(d)

    # stream the key counts of our children
    for v in d.itervalues():
        if isinstance(v, dict):
            for x in _counter(v):
                yield x

def count_faster(d):
    return sum(_counter(d))

これにより、もう少しパフォーマンスが向上します。

In [1]: %timeit sum_keys(dict_test)
100000 loops, best of 3: 4.12 µs per loop

In [2]: %timeit count_faster(dict_test)
100000 loops, best of 3: 3.29 µs per loop
30
donkopotamus

どう?

n = sum([len(v)+1 for k, v in dict_test.items()])

あなたがしているのは、すべてのキーkと値vを反復処理することです。値vはサブディクショナリです。これらのディクショナリの長さを取得し、サブディクショナリのインデックスに使用されるキーを含めるために1つ追加します。

その後、リストを合計して、キーの完全な数を取得します。

編集:

明確にするために、このスニペットは、要求された辞書の辞書に対してのみ機能します。辞書の辞書ではない...
したがって、ネストされた例には使用しないでください:)

9
MaxBenChrist

より一般的な方法として、再帰関数とジェネレーター式を使用できます。

_>>> def count_keys(dict_test):
...     return sum(1+count_keys(v) if isinstance(v,dict) else 1 for _,v in dict_test.iteritems())
... 
_

例:

_>>> dict_test = {'a': {'c': '2', 'b': '1', 'e': {'f': {1: {5: 'a'}}}, 'd': '3'}}
>>> 
>>> count(dict_test)
8
_

:In python 3.Xは、dict.items()の代わりにiteritems()メソッドを使用します。

この関数が受け入れられた答えよりも速いことを示す、受け入れられた答えのベンチマーク:

_from timeit import timeit

s1 = """
def sum_keys(d):
    return 0 if not isinstance(d, dict) else len(d) + sum(sum_keys(v) for v in d.itervalues())

sum_keys(dict_test)
"""

s2 = """
def count_keys(dict_test):
    return sum(1+count_keys(v) if isinstance(v,dict) else 1 for _,v in dict_test.iteritems())

count_keys(dict_test)
   """

print '1st: ', timeit(stmt=s1,
                      number=1000000,
                      setup="dict_test = {'a': {'c': '2', 'b': '1', 'e': {'f': {1: {5: 'a'}}}, 'd': '3'}}")
print '2nd : ', timeit(stmt=s2,
                       number=1000000,
                       setup="dict_test = {'a': {'c': '2', 'b': '1', 'e': {'f': {1: {5: 'a'}}}, 'd': '3'}}")
_

結果:

_1st:  4.65556812286
2nd :  4.09120802879
_
9
Kasrâmvd

ジェネレーター関数と yield from 新しい構文Python3.x。これは、任意のネストされた辞書で機能します。

>>> from collections import Mapping
>>> def count_keys(mydict):
...     for key, value in mydict.items():
...         if isinstance(value, Mapping):
...             yield from count_keys(value)
...     yield len(mydict)
... 
>>> dict_test = {'key2': {'key_in3': 'value', 'key_in4': 'value'}, 'key1': {'key_in2': 'value', 'key_in1': 'value'}}
>>> sum(count_keys(dict_test))
6

Python 2.xでは、これを行う必要があります。

>>> def count_keys(mydict):
...     for key, value in mydict.items():
...         if isinstance(value, Mapping):
...             for item in count_keys(value):
...                 yield 1
...         yield 1
... 
>>> sum(count_keys(dict_test))
6
6
styvane

ネストされた辞書のキーの総数を見つけるための再帰関数は次のとおりです...

s=0
def recurse(v):
   if type(v)==type({}):
     for k in v.keys():
      global s
      s+=1
      recurse(v[k])
5
Dharmik

何かのようなもの:

print len(dict_test) + sum(len(v) for v in dict_test.values())

len(dict)はディクショナリ内のキーの数を返します。したがって、ネストされている方法と、すべての値がディクショナリであることがわかっていると仮定します。

counter = len(outer_dict)
for v in outer_dict.values :
    counter += len(v)

これをリスト内包で包むことができます:

counter = len(outer_dict)
counter += sum([len(inner_dict) for inner_dict in outer_dict.values])

おそらく最もPythonicです。次のように拡張できます。

counter = len(outer_dict)
counter += sum([len(inner_dict) if isinstance(inner_dict, dict) else 0 for inner_dict in outer_dict.values])

しかし、私はこれがかなり読めないと思う傾向があります。

4
phil_20686

そのためにpandas DataFrameを使用してみてください:

_>>> import pandas as pd
>>> data = {'1': {'2': 'a', '3': 'b'}, '4': {'5': 'c', '6': 'd'}, '7': {'5': 'x'}}
>>> df = pd.DataFrame(data)
>>> print (df.count().sum() + len(df.columns))  # 8
_

pd.DataFrame(data)行は、辞書をN x Mマトリックスに変換します。Nは「親」キーの数、Mは一意の子キーの数です。

_     1    4    7
2    a  NaN  NaN
3    b  NaN  NaN
5  NaN    c    x
6  NaN    d  NaN
_

[行、列]ごとに値またはNaNがあります。 NaN以外の値をカウントするだけで、子キーの数が得られ、列(親キー)の数を表すlen(df.columns)が追加されます。

4
matino

再帰関数:

def count_keys(some_dict):
    count = 0
    for key in some_dict:
        if isinstance(some_dict[key], dict):
            count += count_keys(some_dict[key])
        count += 1
    return count
4
Konstantyn

これを試して、

l = len(dict_test)
for k in dict_test:
    l += len(dict_test[k])
3
Dharmik