Комментарий для сопоставления контейнер Python, в котором каждый элемент является ключевым


Я хотел бы иметь контейнер Python, в котором каждый элемент является одним из ключевых (как в наборе), но по-прежнему поддерживает сопоставление (как дикт) между элементами. Чтобы получить контейнер, который поддерживает эту идею элементов должны быть уникальными как в наборе и сопоставление между элементами должен быть двунаправленным. Я не мог найти такую вещь, поэтому я попытался реализовать это сам.

Так как это первая структура данных, я реализовал себя в Python, я хотел бы спросить, если у кого-то есть замечания или советы для меня.

Редактировать: обновленный вариант в соответствии с рекомендациями @Winston и добавил более удачный пример

import copy

class Network(object):
    """
    A network is a container similar to a set in which
    the elements can be mapped to each other (be connected).
    The Elements in a network are called entities and are
    unique in the network.

    Single entities can be inserted into the network by
    using the method insert(entity).

    Connections between entities are made using the method
    connect(entity1, entity2), which automatically inserts
    the entity/-ies into the network if not existent beforehand.

    Calling network[entity] returns a subset of the network,
    containig all the entities connected to the given entity.

    Removing an entity from the network results in removing
    all its connections in the network aswell.
    """

    def __init__(self):
        self._db = {}

    def __delitem__(self, entity):
        self.remove(entity)

    def __getitem__(self, entity):
        """
        Returns a subset of the network, containig all the
        entities connected to the given entity
        """
        return self._db.__getitem__(entity)

    def __iter__(self):
        return self._db.__iter__()

    def __len__(self):
        """Returns the number of entities in the network"""
        return self._db.__len__()

    def __repr__(self):
        return self._db.__repr__()

    def __str__(self):
        return self._db.__str__()

    def are_connected(self, entity1, entity2):
        """Test for a connection between two entities."""
        return entity2 in self._db[entity1] #and entity1 in self._db[entity2]

    def clear(self):
        """Removes all entities from the network"""
        self._db.clear()

    def connect(self, entity1, entity2):
        """ Connects entity1 and entity2. Automatically inserts the
        entity/-ies into the network if not existent beforehand."""
        self._db.setdefault(entity1, set()).add(entity2)
        self._db.setdefault(entity2, set()).add(entity1)

    def connect_many(self, entity, seq):
        """Connects entity with all entities in seq."""
        for e in seq:
            self.connect(entity, e)

    def copy(self):
        """Returns a deep copy of the network"""
        return copy.deepcopy(self)

    def entities(self):
        """Returns a set of the entities in the network."""
        return set(self._db.keys())

    def get(self, entity, default=None):
        """Return the set of connected entities of entity if entity is in
        the network, else default. If default is not given, it defaults to
        None, so that this method never raises a KeyError."""
        return self._db.get(entity, default)

    def insert(self, entity):
        """Inserts an entity into the network."""
        self._db.setdefault(entity, set())

    def isolate(self, entity):
        """Removes all connections of an entity"""
        for e in self[entity]:
            if e != entity:
                self[e].remove(entity)
        self._db[entity].clear()

    def pop(self, entity):
        """Removes an entity from the network and returns the set of entities
        it was previously connected with."""
        temp = self[entity]
        self.remove(entity)
        return temp

    def remove(self, entity):
        """Removes an entity and all its connections from the network."""
        for e in self[entity]:
            if e != entity:
                self[e].remove(entity)
        del self.db[entity]

    def setdefault(self, entity):
        """If entity is in the network, return the set of connected entites.
        If not, insert entity and return default. default defaults to an empty set."""
        return self._db.setdefault(entity, set())

    def unique_mapping(self, entity):
        """If the given entity is mapped to a single other entity this entity is returned,
        otherwise a ValueError exception is raised."""
        entity_set = self._db[entity]
        if len(entity_set) == 1:
            return next(iter(entity_set))
        else:
            raise ValueError("The entity '%s' has no unique mapping." % entity)

    def update(self, netw):
        """Updates the network with another given network. Equal entities are merged."""
        for entity in netw:
            for e in netw[entity]:
                self.connect(entity,e)

Пример использования:

>>> friends = Network()
>>> friends.connect("Peter","John")
>>> friends.connect("Peter","Paul")
>>> friends.connect("Steve","John")
>>> friends.connect("Bill","Steve")
>>> friends.connect("Mark","John")
>>> print "%s are friends of John" % ", ".join(friends["John"])
Steve, Peter, Mark are friends of John
>>> print "%s is Bills only friend" % friends.unique_mapping("Bill")
Steve is Bills only friend

Комментарии/советы по поводу общей реализации структур данных в Python и стиль моей реализации так же уважаемо, как предложения, касающиеся производительности, семантика и использование этого контейнера. В основном не стесняйтесь, чтобы critizise или дать совет на что-нибудь можно придумать. Большое спасибо!



273
3
задан 4 октября 2011 в 11:10 Источник Поделиться
Комментарии
1 ответ

class network(object):

Руководство по стилю Python рекомендует верблюжьего для имен классов

    """
A network is a container similar to a set in which
the elements can be mapped to each other (be connected).
The Elements in a network are called entities and are
unique in the network.

Single entities can be inserted into the network by
using the method insert(entity).

Connections between entities are made using the method
connect(entity1, entity2), which automatically inserts
the entity/-ies into the network if not existent beforehand.

Calling network[entity] returns a subset of the network,
containig all the entities connected to the given entity.

Removing an entity from the network results in removing
all its connections in the network aswell.
"""

def __init__(self):
self.db = dict()

Я бы назвал это _db, чтобы было понятно, что это личное. Пустые словари, как правило, создаются с {}

    def __delitem__(self, entity):
self.remove(entity)

def __getitem__(self, entity):
"""
Returns a subset of the network, containig all the
entities connected to the given entity
"""
return self.db.__getitem__(entity)

def __iter__(self):
return self.db.__iter__()

def __len__(self):
"""Returns the number of entities in the network"""
return self.db.__len__()

def __repr__(self):
return self.db.__repr__()

def __str__(self):
return self.db.__str__()

def are_connected(self, entity1, entity2):
"""Test for the presence of a connection between entity1 and entity2."""
return entity1 in self.db[entity2] and entity2 in self.db[entity1]

Вам действительно нужно, чтобы проверить как?

    def clear(self):
self.db.clear()

def connect(self, entity1, entity2):
"""
Connects entity1 and entity2. Automatically inserts
the entity/-ies into the network if not existent beforehand.
"""
self.db.setdefault(entity1, set()).add(entity2)
self.db.setdefault(entity2, set()).add(entity1)

def connect_many(self, entity, seq):
"""Connects entity with all entities in seq."""
for e in seq:
self.connect(entity, e)

def copy(self):
return self.db.copy()

def entities(self):
"""Returns a set of the entities in the network."""
return set(self.db.keys())

Почему вы возвращаете этот набор? Кажется, нарушить симметрию и все остальное возвращает дикт, которые являются списками или генераторы.

    def get(self, entity, default=None):
return self.db.get(entity, default)

def insert(self, entity):
"""Inserts an entity into the network."""
self.db.setdefault(entity, set())

def isolate(self, entity):
"""Removes all connections of an entity"""
for e in self[entity]:
if e != entity:
self[e].remove(entity)
self.db[entity].clear()

def pop(self, entity):
temp = self[entity]
self.remove(entity)
return temp

def remove(self, entity):
"""Removes an entity and all its connections from the network."""
for e in self[entity]:
if e != entity:
self[e].remove(entity)
self.db.__delitem__(entity)

Почему не Дель самостоятельно.дБ[сущности]?

    def setdefault(self, entity):
return self.db.setdefault(entity, set())

Вы отклоняетесь от интерфейса дикт здесь. У тебя есть веская причина?

    def unique_mapping(self, entity):
"""If the given entity is mapped to a single entity this entity is returned"""
if len(self.db[entity]) == 1:
return next(iter(self.db[entity]))

Вы можете хотеть избежать извлечения собственной.дБ[сущности] несколько раз

        else:
return False

Вы должны бросать исключение, а не возвращает значение сигнальной метки. Если вы настаивает на возвращении стража используйте значение None.

    def update(self, netw):
"""Updates the network with another given network. Equal entities are merged."""
for entity in netw:
for e in netw[entity]:
self.connect(entity,e)

Вы можете получать этот класс наследовать от дикт, и тогда вы смогли бы избежать все

def foo(self):
return self.db.foo()

Но тогда вы могли бы сделать методы, которые вы не хотите также. Это решение.

5
ответ дан 6 октября 2011 в 12:10 Источник Поделиться