Python中是否有KeyedCollection的等价物,即元素拥有(或动态生成)自己的键的集合?
即。这里的目标是避免将密钥存储在两个地方,因此字典不太理想(因此问题)。
答案 0 :(得分: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
代替dict
,其子类为KeyedObject
(其中get_key
根据某些对象属性返回有效密钥。)
答案 1 :(得分:2)
鉴于你的约束,每个试图使用dict
实现你正在寻找的东西的人正在咆哮错误的树。相反,您应该编写一个覆盖list
的{{1}}子类来提供您想要的行为。我已经编写了它,因此它首先尝试通过索引获取所需的项目,然后回退到按所包含对象的__getitem__
属性搜索项目。 (如果对象需要动态确定,这可能是属性。)
如果您不想在某处复制某些内容,则无法避免线性搜索;如果你不允许它使用字典来存储密钥,我确信C#实现完全一样。
key
您可能还希望以类似方式覆盖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()
的API,它也可以像列表一样工作。
答案 2 :(得分:1)
我不是一个C#呃,但我认为字典是你需要的。
http://docs.python.org/tutorial/datastructures.html#dictionaries
http://docs.python.org/tutorial/datastructures.html
或者可能是名单:
答案 3 :(得分:1)
@Mehrdad说:
因为在语义上,它没有那么多意义。当一个对象 知道它的关键,把它放在字典中没有意义 - 就是这样 不是键值对。它更像是一个语义问题 其他
使用此约束,Python中没有任何内容可以执行您想要的操作。我建议你使用dict而不用担心语义上的这种详细程度。 @Gabi Purcaru的答案显示了如何使用所需的界面创建对象。为什么要对内部工作方式感到困扰?
可能是C#的KeyedCollection在幕后做了同样的事情:询问对象的密钥,然后存储密钥以便快速访问。实际上,来自文档:
默认情况下,KeyedCollection(Of TKey,TItem)包含查找 您可以使用Dictionary属性获取的字典。当一个 item被添加到项目密钥KeyedCollection(Of TKey,TItem)中 被提取一次并保存在查找字典中以便更快 搜索。通过指定字典来覆盖此行为 创建KeyedCollection时创建阈值(Of TKey, TItem)。查找字典是第一次创建的数量 元素超过了这个阈值。如果指定-1作为阈值, 永远不会创建查找字典。
答案 4 :(得分:0)
为什么不简单地使用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
答案 5 :(得分: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'}
答案 6 :(得分:0)
set()
怎么样?元素可以有自己的k
答案 7 :(得分:0)
再详细一点,来自@Gabi Purcaru的答案已经正确答案了,这里有一个与gabi相同的课程,但是也要检查键上的正确给定类型value(作为.net KeyedCollection的TKey和TValue)。
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