PythonのKeyedCollectionに相当するもの、つまり要素が独自のキーを持っている(または動的に生成する)セットはありますか?
つまり、ここでの目標は、キーを2つの場所に保存しないようにすることです。したがって、辞書は理想的とは言えません(したがって、質問です)。
PythonのKeyedCollectionに相当するもの、つまり要素が独自のキーを持っている(または動的に生成する)セットはありますか?
つまり、ここでの目標は、キーを2つの場所に保存しないようにすることです。したがって、辞書は理想的とは言えません(したがって、質問です)。
これは非常に簡単にシミュレートできます。
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
代わりにを使用できます(オブジェクトプロパティに基づいて有効なキーを返します)。dict
KeyedObject
get_key
あなたの制約を考えると、あなたが探しているものを使用して実装しようとしている人は皆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があります。
私はC#の人ではありませんが、辞書はあなたが必要としているものだと思います。
http://docs.python.org/tutorial/datastructures.html#dictionaries
http://docs.python.org/tutorial/datastructures.html
または多分リスト:
@Mehrdadは言った:
意味的には、あまり意味がありません。オブジェクトがそのキーを知っている場合、それを辞書に入れることは意味がありません-それはキーと値のペアではありません。それは何よりも意味論的な問題です。
この制約があるため、Pythonには必要なことを実行するものはありません。セマンティクスのこのレベルの詳細について心配するのではなく、dictを使用することをお勧めします。@Gabi Purcaruの回答は、必要なインターフェイスを使用してオブジェクトを作成する方法を示しています。なぜそれが内部でどのように機能しているかについて悩むのですか?
C#のKeyedCollectionが内部で同じことを行っている可能性があります。つまり、オブジェクトにキーを要求してから、高速アクセスのためにキーを保存します。実際、ドキュメントから:
デフォルトでは、KeyedCollection(Of TKey、TItem)には、Dictionaryプロパティで取得できるルックアップディクショナリが含まれています。アイテムがKeyedCollection(Of TKey、TItem)に追加されると、アイテムのキーが1回抽出され、ルックアップディクショナリに保存されて検索が高速化されます。この動作は、KeyedCollection(Of TKey、TItem)を作成するときにディクショナリ作成のしきい値を指定することで上書きされます。ルックアップディクショナリは、要素の数がそのしきい値を初めて超えたときに作成されます。しきい値として-1を指定すると、ルックアップディクショナリは作成されません。
どうset()
ですか?要素は独自のkを持つことができます
単純に使用してみません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
これがあなたの意図したものかどうかはわかりませんが、この辞書に追加すると、この辞書は独自のキーを作成します...
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'}
@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