3

編集:@BrenBarnが指摘したように、オリジナルは意味がありませんでした。

dictのリスト(提供csv.DictReader:すべてにstrキーと値があります)を考えると、すべてをセットに詰め込んで重複を削除すると便利ですが、ハッシュ化できないため、これを直接行うことはできませんdict。いくつかの既存の 質問は、集合/辞書を偽造する方法に触れていますが、どちらの方法を優先すべきかについては触れていません。__hash__()

# i. concise but ugly round trip
filtered = [eval(x) for x in {repr(d) for d in pile_o_dicts}]

# ii. wordy but avoids round trip
filtered = []
keys = set()
for d in pile_o_dicts:
    key = str(d)
    if key not in keys:
        keys.add(key)
        filtered.append(d)

# iii. introducing another class for this seems Java-like?
filtered = {hashable_dict(x) for x in pile_o_dicts}

# iv. something else entirely

PythonのZenの精神で、「それを行うための明白な方法」とは何ですか?

4

3 に答える 3

4

あなたのサンプルコードに基づいて、私はあなたの質問をあなたが文字通り言っていることとは少し違うものだと思います。実際にはオーバーライドしたくありません__hash__()。線形時間で重複を除外したいだけですよね?したがって、ディクショナリごとに次のことを確認する必要があります。1)すべてのキーと値のペアが表され、2)安定した順序で表されます。キーと値のペアのソートされたタプルを使用できますが、代わりに、を使用することをお勧めしfrozensetます。frozensetsはハッシュ可能であり、ソートのオーバーヘッドを回避します。これにより、パフォーマンスが向上するはずです(この回答で確認できるようです)。欠点は、タプルよりも多くのメモリを消費することです。そのため、ここでは空間と時間のトレードオフがあります。

また、コードはセットを使用してフィルタリングを実行しますが、それはあまり意味がありません。eval辞書を使用する場合、その醜いステップは必要ありません。

filtered = {frozenset(d.iteritems()):d for d in pile_o_dicts}.values()

または、Python 3では、辞書ビューではなくリストが必要だと仮定します。

filtered = list({frozenset(d.items()):d for d in pile_o_dicts}.values())

これらは両方とも少し不格好です。読みやすくするために、2行に分割することを検討してください。

dict_o_dicts = {frozenset(d.iteritems()):d for d in pile_o_dicts}
filtered = dict_o_dicts.values()

別の方法は、順序付けられたタプルのタプルです。

filtered = {tuple(sorted(d.iteritems())):d for d in pile_o_dicts}.values()

そして最後の注意:これには使用しないでくださいrepr。等しいと評価される辞書は、異なる表現を持つことができます。

>>> d1 = {str(i):str(i) for i in range(300)}
>>> d2 = {str(i):str(i) for i in range(299, -1, -1)}
>>> d1 == d2
True
>>> repr(d1) == repr(d2)
False
于 2012-09-05T23:11:29.977 に答える
3

巧妙に名前が付けられたpile_o_dictsは、アイテムリストを並べ替えることで標準形に変換できます。

 groups = {}
 for d in pile_o_dicts:
     k = tuple(sorted(d.items()))
     groups.setdefault(k, []).append(d)

これにより、同一の辞書がグループ化されます。

FWIWでは、sorted(d.items())同じキーワード引数を持つ関数呼び出しを認識するために、functools.lru_cache()の標準ライブラリで現在使用されている手法が使用されています。IOW、このテクニックは試されて真実です:-)

于 2012-09-06T03:07:25.350 に答える
2

dictがすべて同じキーを持っている場合は、namedtuple

>>> from collections import namedtuple
>>> nt = namedtuple('nt', pile_o_dicts[0])
>>> set(nt(**d) for d in pile_o_dicts)
于 2012-09-05T23:15:31.487 に答える