11

この質問は、Python での完全な Perl 自動有効化の実装に関するものです。以前にも同様の質問があったことは知っていますが、これまでのところ、最良の答えは「Python でネストされた辞書を実装する最良の方法は何ですか?」です。しかし、私はこれをやろうとしています:

a['x']['y'].append('z')

最初に宣言せずa['x']['y'] = []に、または宣言せずにa['x'] = {}。(Perlではできることに注意してくださいpush @{$a->{x}{y}}, 'z';。)

私は知っていてdictlistクラスは混在しないので、これは難しいですが、誰かがおそらく継承されたクラスを作成することを含む独創的な解決策を持っているかどうかを知りたいのですが、それに新しいメソッドをdict定義しましたか?append

また、これにより、Perl に固執するように頼まれる Python 純粋主義者の一部が気を失う可能性があることもわかっています。でも、挑戦するだけでも何か見てみたい。

4

5 に答える 5

16
a = collections.defaultdict(lambda: collections.defaultdict(list))
于 2010-03-12T21:26:17.543 に答える
2

おそらく、これにより、辞書内の任意の数の「ディメンション」の必要性が解決されます。

a= collections.defaultdict(list)

コードの唯一の変更点は次のとおりです。

a['x', 'y'].append('z')

もちろん、このソリューションが必要なものになるかどうかは、次の2つの条件によって異なります。

  1. 「最初の次元」に「x」などが含まれるすべてのリストに簡単にアクセスする必要があるかどうか</li>
  2. Perlが魔法のようにあなたをもっと喜ばせる方法に固執しているかどうか:)

これらの2つの条件のいずれかが当てはまる場合、私の解決策は役に立ちません。

于 2010-04-09T00:23:36.660 に答える
2

Ignacio's answer を拡張して、Python 辞書からより魔法のような動作を明示的に要求できるようにするいくつかの追加オプションを提示します。このように記述されたコードの保守性は疑わしいままですが、「このようなデータ構造は保守可能か?」という問題であることを明確にしたかったのです。(私は疑問を持っています)「Pythonをこのように動作させることはできますか?」ではありません (確かにできます)。

名前空間の側面で任意のレベルのネストをサポートするには、(ラムダを使用する代わりに) 関数に名前を付けて自己参照にするだけです。

>>> from collections import defaultdict
>>> def autodict(): return defaultdict(autodict)
...
>>> a = autodict()
>>> a[1][2][3] = []
>>> type(a[1])
<class 'collections.defaultdict'>
>>> type(a[1][2])
<class 'collections.defaultdict'>
>>> type(a[1][2][3])
<class 'list'>
>>> a[1][2][3]
[]

ただし、これにより、追加する前にリストを明示的に設定する必要があるという「問題」が発生します。それに対する Python の答えはsetdefaultメソッドにありますcollections.defaultdict

>>> a.setdefault(3, []).append(10)
>>> a.setdefault(3, []).append(11)
>>> a[3]
[10, 11]
>>> a[2].setdefault(3, []).append(12)
>>> a[2].setdefault(3, []).append(13)
>>> a[2][3]
[12, 13]
>>> a[1][2].setdefault(3, []).append(14)
>>> a[1][2].setdefault(3, []).append(15)
>>> a[1][2][3]
[14, 15]

collections.defaultdict実際に行うことは、常に同じ 2 番目のパラメーターを渡すという一般的なケースをよりdict.setdefault使いやすくすることです。このようなより複雑なケースでは、処理できないdict.setdefault側面に直接使用できます。collections.defaultdict

于 2012-08-28T02:26:50.573 に答える
2

辞書が必要なのかリストが必要なのかが事前にわからないため、自動有効化をリストと組み合わせることはできません。リンクされた質問からのNoskloの回答に基づいて作業しない限り、リストの「機能」を基礎となる辞書に追加します。基本的に、キーの「ソート」順序を想定し、常にリスト メソッドで使用します。例としてこれを行いました:

class AutoVivification(dict):
    """Implementation of perl's autovivification feature. Has features from both dicts and lists,
    dynamically generates new subitems as needed, and allows for working (somewhat) as a basic type.
    """
    def __getitem__(self, item):
        if isinstance(item, slice):
            d = AutoVivification()
            items = sorted(self.iteritems(), reverse=True)
            k,v = items.pop(0)
            while 1:
                if (item.start < k < item.stop):
                    d[k] = v
                elif k > item.stop:
                    break
                if item.step:
                    for x in range(item.step):
                        k,v = items.pop(0)
                else:
                    k,v = items.pop(0)
            return d
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            value = self[item] = type(self)()
            return value

    def __add__(self, other):
        """If attempting addition, use our length as the 'value'."""
        return len(self) + other

    def __radd__(self, other):
        """If the other type does not support addition with us, this addition method will be tried."""
        return len(self) + other

    def append(self, item):
        """Add the item to the dict, giving it a higher integer key than any currently in use."""
        largestKey = sorted(self.keys())[-1]
        if isinstance(largestKey, str):
            self.__setitem__(0, item)
        elif isinstance(largestKey, int):
            self.__setitem__(largestKey+1, item)

    def count(self, item):
        """Count the number of keys with the specified item."""
        return sum([1 for x in self.items() if x == item])

    def __eq__(self, other):
        """od.__eq__(y) <==> od==y. Comparison to another AV is order-sensitive
        while comparison to a regular mapping is order-insensitive. """
        if isinstance(other, AutoVivification):
            return len(self)==len(other) and self.items() == other.items()
        return dict.__eq__(self, other)

    def __ne__(self, other):
        """od.__ne__(y) <==> od!=y"""
        return not self == other

これは、ダッドキーに対して動的に生成する基本的な自動有効化機能に従います。ただし、ここにリストされているメソッドの一部も実装しています。これにより、準リスト/辞書のように振る舞うことができます。

リストの残りの機能については、リストされているメソッドを追加してください。リストメソッドを使用して辞書として扱っています。list メソッドが呼び出されると、保持されている項目の順序について、つまり、文字列は整数より下位にソートされ、キーは常に「ソートされた」順序であると仮定されます。

これらのメソッドの例として、追加もサポートしています。これは私自身のユースケースから来ています。AutoVivified ディクショナリからアイテムを追加する必要がありましたが、存在しない場合は、新しいAutoVivificationオブジェクトが作成されて返されます。それらには整数の「値」がないため、これを行うことはできません:

rp = AutoVivification()
rp['a']['b'] = 3
rp['a']['b'] + rp['q']

何かがそこにあるかどうかわからないので、それは目的に反しますが、とにかくデフォルトが必要です。__add__そのため、 and__radd__メソッドを追加しました。length基礎となるディクショナリの を値として使用するintegerため、新しく作成された AV オブジェクトの値は追加のためにゼロになります。キーに AV オブジェクト以外の何かが含まれている場合、実装されている場合はその追加メソッドを取得します。

于 2012-05-09T15:19:29.953 に答える