Python 集和字典

在一个有序的集合中,每一项的值和位置都很重要,并且每一项都是通过其位置来访问的。对于一个无序的集合来说,用户可以插入、访问或删除项,但是却不能访问第i个项、下一个项或前一个项。无序集合的一些示例是包、集和字典。

集(set)是没有特定顺序的项的一个集合,从用户的视角来看,集中的项是唯一的,也就是说,集中没有重复的项。

Python的set类

Python包含了一个set类,这个类的最常用的方法如下:

Set类的常用操作
Set方法作用
s = set()创建一个空的集并将其分配给s
s = set(anIterable)创建一个集,其中包含了anIterable对象中的唯一的项(如字符串、列表或字典),并且将其分配给s
s.add(item)如果item还不在s中的话,将其添加到s中
s.remove(item)从s中删除item,先验条件:item必须在s中
s.__len__()等同于len(s),返回s中当前的项的数目
s.__iter__()返回s上的一个迭代器。支持对s使用for循环,按照不确定的顺序访问项
s.__str__()等同于str(s),返回一个字符串,其中包含了s的字符串表示
s.__contains__(item)等同于item in s,如果item在s中,返回True
s1.__or__(s2)集的并集,返回一个集,其中包含了s1和s2中的项
s1.__and__(s2)集的交集,返回一个集,其中包含了既在s1中也在s2中的项
s1.__sub__(s2)集的差集,返回一个集,其中包含了在s1中但不在s2中的项
s1.issubset(s2)如果s1是s2的子集,返回True

当set构造方法接收一个列表作为参数的时候,列表中的项会复制到集中,并忽略掉重复的项。

示例:

>>> A = set([0,1,2])
>>> B = set()
>>> 1 in A
True
>>> A & B
set()
>>> B.add(1)
>>> B.add(1)
>>> B.add(5)
>>> B
{1, 5}
>>> A & B
{1}
>>> A | B
{0, 1, 2, 5}
>>> A - B
{0, 2}
>>> B.remove(5)
>>> B
{1}
>>> B.issubset(A)
True
>>> for item in A:
...     print(item,end = "")
...
012
集的应用

在数据库管理方面,要响应包含了两个键的联合的一个查询,而这个查询是通过和这些键相关项的集的交集而构建的。

集的基于数组和链表的实现

我们可以通过数组或链表结构来包含集中的数据项,只要在结构中找到了要删除的项,链表结构就支持常数时间的删除,但是在集中添加和删除项需要线性的搜索,另一种策略叫哈希(hash),它试图以近似随机的方式访问一个数组,以实现插入、删除和搜索。

集实际上是包含了唯一的数据项和一些额外方法的包,集的简单实现就是将之前介绍的包(ArrayBag、LinkedBag)子类化。集的特定的方法__add__、__or__、__sub__、issubset也包含在每一个集类之中,由于这些方法只是运行set接口中的其他方法,在所有的实现中,这些方法都具有相同的代码,因此,可以在另一个名为AbstractSet的父类中实现它们。由于Python支持多继承,所以一个给定的类可以有多个父类。


AbstractSet类

AbstractSet类只是泛型的集方法__and__、__or__、__sub__和issubset的一个库,这个类是object的一个子类,因为其他的集类已经从包类继承了其他的集合资源。

class AbstractSet(object):
    """Generic set method implementations."""

    # Accessor methods
    def __or__(self, other):
        """Returns the union of self and other."""
        return self + other

    def __and__(self, other):
        """Returns the intersection of self and other."""
        intersection = type(self)()
        for item in self:
            if item in other:
                intersection.add(item)
        return intersection

    def __sub__(self, other):
        """Returns the difference of self and other."""
        difference = type(self)()
        for item in self:
            if not item in other:
                difference.add(item)
        return difference

    def issubset(self, other):
        """Returns True if self is a subset of other
        or False otherwise."""
        for item in self:
            if not item in other:
                return False
        return True

ArraySet类

ArraySet类从一个父类ArrayBag继承了isEmpty、__len__、__iter__、__add__、__eq__、remove方法,从另一个父类AbstractSet类继承了__and__、__or__、__sub__、issubset方法,ArraySet实际上将这些方法混合到一起,以支持一种新的对象类型,然而这样一来,ArraySet必须覆盖ArrayBag的add方法,以防止插入重复的项

from arraybag import ArrayBag
from abstractset import AbstractSet

class ArraySet(ArrayBag, AbstractSet):
    """An array-based set implementation."""

    # Constructor
    def __init__(self, sourceCollection = None):
        """Sets the initial state of self, which includes the
        contents of sourceCollection, if it's present."""
        ArrayBag.__init__(self, sourceCollection)

    # Mutator methods
    def add(self, item):
        """Adds item to self."""
        if not item in self:
            ArrayBag.add(self, item)


字典

字典可以看作是项的键/值对的集。然而,字典的接口和集的接口有很大不同。通过使用Python的dict类型,我们知道值是通过下标运算符[]在给定的键上插入或替换的。

字典集合的接口
方法作用
d = <dictionary type>(sourceCollection = None)创建一个字典,并且将其分配给d。先验条件:sourceCollection必须是另一个字典或键/值元组的一个列表
d.__getItem__(key)等同于d[key],如果key存在,返回和key相关的值,否则引发KeyError
d.__setItem__(key,value)等同于d[key] = value,如果key存在,用value替代其相关的值,否则,插入键/值条目
d.pop(key)如果key存在的话,删除键/值条目并返回相关的值,否则引发一个KeyError
d.__iter__()等同于iter(d)或key in d,返回d中的键上的一个迭代器
d.keys()返回d中的键上的一个迭代器
d.values()返回d中的值上的一个迭代器
d.items()返回d中的项(键/值对)上的一个迭代器
基于数组和基于链表的字典实现

为了实现字典,我们首先添加一个新的AbstractDict类,作为AbstractCollection的一个子类,这个新的类现在负责__str__、__add__、__eq__、__contains__、__iter__、keys、values和items方法。

具体类ArrayDict和LinkedDict随后作为AbstractDict的子类出现,它们负责__iter__、__clear__、__getitem__、__setitem__和pop方法。下图是这些类之间的关系框图。


Item类

字典中的项包含两个部分,一个键和一个值,字典的每一个实现都包含项,每个键/值对都包含在一个Item对象中。Item类包含了一些比较方法,它允许程序员测试两个条目的相等性,或者在有序的字典中对它们排序。

class Item(object):
    """Represents a dictionary item.
    Supports comparisons by key."""

    def __init__(self, key, value):
        self.key = key
        self.value = value

    def __str__(self):
        return str(self.key) + ":" + str(self.value)

    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.key == other.key

    def __lt__(self, other):
        if type(self) != type(other): return False
        return self.key < other.key

    def __le__(self, other):
        if type(self) != type(other): return False
        return self.key <= other.key

注意:这个类和AbstractDict类放在了同一个模块中。

AbstractDict类

AbstractDict类包含了所有的调用其他字典方法来完成其工作的方法。这些方法也包括一些AbstractCollection方法,如__str__、__add__、__eq__,必须覆盖这些方法以支持类似字典的行为

此外,AbstractDict中的__init__方法现在需要将sourceCollection(必须是键/值对的一个集合)中的项复制到新的字典对象中。注意:这里必须不调用AbstractCollection中的__init__方法。

from abstractcollection import AbstractCollection

class AbstractDict(AbstractCollection):
    """Common data and method implementations for dictionaries."""

    def __init__(self, sourceCollection):
        """Will copy items to the collection from sourceDictionary
        if it's present."""
        AbstractCollection.__init__(self)
        if sourceCollection:
            for key, value in sourceCollection:
                self[key] = value

    def __str__(self):
        return " {" + ", ".join(map(str, self.items())) + "}"

    def __add__(self, other):
        """Returns a new dictionary containing the contents
        of self and other."""
        result = type(self)(map(lambda item: (item.key, item.value),
                                self.items()))
        for key in other:
            result[key] = other[key]
        return result

    def __eq__(self, other):
        """Returns True if self equals other,
        or False otherwise."""
        if self is other: return True
        if type(self) != type(other) or \
           len(self) != len(other):
            return False
        for key in self:
            if not key in other:
                return False
        return True

    def keys(self):
        """Returns an iterator on the keys in the dictionary."""
        return iter(self)

    def values(self):
        """Returns an iterator on the values in the dictionary."""
        return iter(map(lambda key: self[key], self))

    def items(self):
        """Returns an iterator on the entries in the dictionary."""
        return iter(map(lambda key: Item(key, self[key]), self))

ArrayDict类

和其他的具体类一样,ArrayDict类负责初始化集合的容器对象,并且实现直接访问该容器的方法。这里的__getitem__、__setitem__、pop方法调用了辅助方法_index来找到目标键。

from abstractdict import AbstractDict, Item

class ArrayDict(AbstractDict):
    """Represents an array-based dictionary."""

    def __init__(self, sourceCollection = None):
        """Will copy items to the collection from sourceCollection
        if it's present."""
        self._items = list()
        AbstractDict.__init__(self, sourceCollection)

    # Accessors
    def __iter__(self):
        """Serves up the keys in the dictionary."""
        cursor = 0
        while cursor < len(self):
            yield self._items[cursor].key
            cursor += 1    

    def __getitem__(self, key):
        """Precondition: the key is in the dictionary.
        Raises: a KeyError if the key is not in the dictionary.
        Returns the value associated with the key."""
        index = self._index(key)
        if index == -1: raise KeyError("Missing: " + str(key))
        return self._items[index].value

    # Mutators
    def __setitem__(self, key, value):
        """If the key is not in the dictionary,
        adds the key and value to it.
        Othwerise, replaces the old value with the new
        value."""
        index = self._index(key)
        if index == -1:
            self._items.append(Item(key, value))
            self._size += 1
        else:
            self._items[index].value = value

    def pop(self, key):
        """Precondition: the key is in the dictionary.
        Raises: a KeyError if the key is not in the dictionary.
        Removes the key and returns the associated value if the
        key in in the dictionary, or returns the default value
        otherwise."""
        index = self._index(key)
        if index == -1: raise KeyError("Missing: " + str(key))
        self._size -= 1
        return self._items.pop(index).value

    def _index(self, key):
        """Helper method for key search."""
        index = 0
        for entry in self._items:
            if entry.key == key:
                return index
            index += 1
        return -1       

_index方法通过键来找到index,self._items存储的是键的一个列表,self._key和self._value继承自item类。


本文是数据结构(用Python实现)这本书的读书笔记!






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值