7

PythonのKeyedCollectionに相当するもの、つまり要素が独自のキーを持っている(または動的に生成する)セットはありますか?

つまり、ここでの目標は、キーを2つの場所に保存しないようにすることです。したがって、辞書は理想的とは言えません(したがって、質問です)。

4

8 に答える 8

3

これは非常に簡単にシミュレートできます。

class KeyedObject(object):
    def get_key(self):
        raise NotImplementedError("You must subclass this before you can use it.")

class KeyedDict(dict):
    def append(self, obj):
        self[obj.get_key()] = obj

これで、のサブクラスのKeyedDict代わりにを使用できます(オブジェクトプロパティに基づいて有効なキーを返します)。dictKeyedObjectget_key

于 2011-07-21T18:14:32.083 に答える
2

あなたの制約を考えると、あなたが探しているものを使用して実装しようとしている人は皆dict、間違ったツリーを吠えています。代わりに、必要な動作を提供するためにlistオーバーライドするサブクラスを作成する必要__getitem__があります。最初にインデックスで目的のアイテムを取得しようとし、次にkey含まれているオブジェクトの属性でアイテムを検索するようにフォールバックするように作成しました。(オブジェクトがこれを動的に決定する必要がある場合、これはプロパティである可能性があります。)

どこかに複製したくない場合は、線形検索を回避する方法はありません。辞書を使用してキーを格納することを許可しない場合、C#の実装はまったく同じことを行うと確信しています。

class KeyedCollection(list):
     def __getitem__(self, key):
         if isinstance(key, int) or isinstance(key, slice):
             return list.__getitem__(key)
         for item in self:
             if getattr(item, "key", 0) == key:
                 return item
         raise KeyError('item with key `%s` not found' % key)

__contains__同様の方法でオーバーライドして、と言うこともできますif "key" in kc...。さらにのようにしたい場合はdict、実装することもできますkeys()dictそれらは同様に非効率的ですが、リストのようにも機能する、のようなAPIがあります。

于 2011-07-21T23:43:51.543 に答える
1

私はC#の人ではありませんが、辞書はあなたが必要としているものだと思います。

http://docs.python.org/tutorial/datastructures.html#dictionaries

http://docs.python.org/tutorial/datastructures.html

または多分リスト:

http://docs.python.org/library/functions.html#list

于 2011-07-21T18:07:28.743 に答える
1

@Mehrdadは言った:

意味的には、あまり意味がありません。オブジェクトがそのキーを知っている場合、それを辞書に入れることは意味がありません-それはキーと値のペアではありません。それは何よりも意味論的な問題です。

この制約があるため、Pythonには必要なことを実行するものはありません。セマンティクスのこのレベルの詳細について心配するのではなく、dictを使用することをお勧めします。@Gabi Purcaruの回答は、必要なインターフェイスを使用してオブジェクトを作成する方法を示しています。なぜそれが内部でどのように機能しているかについて悩むのですか?

C#のKeyedCollectionが内部で同じことを行っている可能性があります。つまり、オブジェクトにキーを要求してから、高速アクセスのためにキーを保存します。実際、ドキュメントから:

デフォルトでは、KeyedCollection(Of TKey、TItem)には、Dictionaryプロパティで取得できるルックアップディクショナリが含まれています。アイテムがKeyedCollection(Of TKey、TItem)に追加されると、アイテムのキーが1回抽出され、ルックアップディクショナリに保存されて検索が高速化されます。この動作は、KeyedCollection(Of TKey、TItem)を作成するときにディクショナリ作成のしきい値を指定することで上書きされます。ルックアップディクショナリは、要素の数がそのしきい値を初めて超えたときに作成されます。しきい値として-1を指定すると、ルックアップディクショナリは作成されません。

于 2011-07-21T23:12:25.797 に答える
0

どうset()ですか?要素は独自のkを持つことができます

于 2011-07-22T03:56:17.297 に答える
0

単純に使用してみませんdictか?キーがすでに存在する場合、キーへの参照がdictで使用されます。無意味に複製されることはありません。

class MyExample(object):
    def __init__(self, key, value):
        self.key = key
        self.value = value

m = MyExample("foo", "bar")
d = {}

d[m.key] = m

first_key = d.keys()[0]
first_key is m.key  # returns True

キーがまだ存在しない場合は、そのコピーが保存されますが、問題はないと思います。

def lame_hash(s):
    h = 0
    for ch in s:
        h ^= ord(ch)
    return h

d = {}
d[lame_hash(m.key)] = m
print d  # key value is 102 which is stored in the dict

lame_hash(m.key) in d  # returns True
于 2011-07-21T18:43:07.913 に答える
0

これがあなたの意図したものかどうかはわかりませんが、この辞書に追加すると、この辞書は独自のキーを作成します...

class KeyedCollection(dict):
    def __init__(self):
        self.current_key = 0
    def add(self, item):
        self[self.current_key] = item

abc = KeyedCollection()
abc.add('bob')
abc.add('jane')
>>> abc
{0: 'bob', 1: 'jane'}
于 2011-07-21T21:35:50.820 に答える
0

@Gabi Purcaruの回答からのすでに正しい回答をもう少し詳しく説明するために、ここでは、gabiのものと同じことを行うが、キーと値(.netのTKeyとTValueとして)の正しい指定されたタイプをチェックするクラスです。 KeyedCollection)。

class KeyedCollection(MutableMapping):
    """
    Provides the abstract base class for a collection (:class:`MutableMappinp`) whose keys are embedded in the values.
    """
    __metaclass__ = abc.ABCMeta
    _dict = None  # type: dict

    def __init__(self, seq={}):
        self._dict = dict(seq)

    @abc.abstractmethod
    def __is_type_key_correct__(self, key):
        """
        Returns: The type of keys in the collection
        """
        pass

    @abc.abstractmethod
    def __is_type_value_correct__(self, value):
        """
        Returns: The type of values in the collection
        """
        pass

    @abc.abstractmethod
    def get_key_for_item(self, value):
        """
        When implemented in a derivated class, extracts the key from the specified element.
        Args:
            value: the element from which to extract the key (of type specified by :meth:`type_value`)

        Returns: The key of specified element (of type specified by :meth:`type_key`)
        """
        pass

    def __assert_type_key(self, key, arg_name='key'):
        if not self.__is_type_key_correct__(key) :
            raise ValueError("{} type is not correct".format(arg_name))

    def __assert_type_value(self, value, arg_name='value'):
        if not self.__is_type_value_correct__(value) :
            raise ValueError("{} type is not correct".format(arg_name))

    def add(self, value):
        """
        Adds an object to the KeyedCollection.
        Args:
            value: The object to be added to the KeyedCollection (of type specified by :meth:`type_value`).
        """
        key = self.get_key_for_item(value)
        self._dict[key] = value

    # Implements abstract method __setitem__ from MutableMapping parent class
    def __setitem__(self, key, value):
        self.__assert_type_key(key)
        self.__assert_type_value(value)
        if value.get_key() != key:
            raise ValueError("provided key does not correspond to the given KeyedObject value")
        self._dict[key] = value

    # Implements abstract method __delitem__ from MutableMapping parent class
    def __delitem__(self, key):
        self.__assert_type_key(key)
        self._dict.pop(key)

    # Implements abstract method __getitem__ from MutableMapping parent class (Mapping base class)
    def __getitem__(self, key):
        self.__assert_type_key(key)
        return self._dict[key]

    # Implements abstract method __len__ from MutableMapping parent class (Sized mixin on Mapping base class)
    def __len__(self):
        return len(self._dict)

    # Implements abstract method __iter__ from MutableMapping parent class (Iterable mixin on Mapping base class)
    def __iter__(self):
        return iter(self._dict)
        pass

    # Implements abstract method __contains__ from MutableMapping parent class (Container mixin on Mapping base class)
    def __contains__(self, x):
        self.__assert_type_key(x, 'x')
        return x in self._dict
于 2017-12-14T15:17:41.140 に答える