Python中的自动增长列表?

时间:2011-02-28 19:14:44

标签: python list

我需要一个类似列表的对象,只要访问大于或等于其长度的插槽号就会“自动增长”,用一些预先指定的默认值填充所有新创建的插槽。 E.g:

# hypothetical DefaultList class
x = DefaultList(list('abc'), default='*')
x[6] = 'g'
print x[2], x[4], x[6], x[8]  # should print 'c * g *'

谢谢!

PS。我知道实现这样的课程并不困难,但我尽可能避免轮胎改造,特别是如果一个特别有效/精心设计的轮子已经存在。

PS2。 dict(或collections.defaultdict)是所需数据结构的可接受实现。为什么,请看这里:http://groups.google.com/group/comp.lang.python/msg/bcf360dfe8e868d1?hl=en

5 个答案:

答案 0 :(得分:3)

class DefaultList(list):
    def __init__(self,*args,**kwargs):
        list.__init__(self,*args)
        self.default=kwargs.get('default',None)
    def __getitem__(self,key):
        # retrieving an item does not expand the list
        if isinstance(key,slice):
            return [self[elt] for elt in range(key.start,key.stop,key.step)]
        else:
            try:
                return list.__getitem__(self,key)
            except IndexError:
                return self.default
    def __setitem__(self,key,value):
        # setting an item may expand the list
        try:
            list.__setitem__(self,key,value)
        except IndexError:
            self.extend([self.default]*(key-len(self)))
            self.append(value)

x = DefaultList(list('abc'), default='*')
print(x)
# ['a', 'b', 'c']
x[6] = 'g'
print(x)
# ['a', 'b', 'c', '*', '*', '*', 'g']
print x[2], x[4], x[6], x[8]  # should print 'c * g *'
# c * g *
print(x[2:9:2])
# ['c', '*', 'g', '*']

答案 1 :(得分:1)

我会使用sparse数据结构(1xn矩阵)。

答案 2 :(得分:1)

你总是可以创建一个处理这个问题的函数:

def fillList(item, slot, myList):
    length = len(myList)
    if slot > length:
        augmentation = [item for x in range(slot-length)]
        myList.extend(augmentation)
    else:
        myList[slot] = item

虽然不是数据结构,但确实能达到你想要的效果。

答案 3 :(得分:0)

使用wheaties解决方案的想法并制作更漂亮的界面:

您可以从列表继承并覆盖列表' getitem (索引)'方法,该方法映射到您的类中的[index]。它应该是这样的:

class GrowingList(list):
    def __getitem__(self, index):
        length = len(self)
        # list is 0 indexed 
        if index >= length:
            tail = [ self.default_value for x in range(index - length + 1)]
            self.extend(tail)


        return super(self.__class__, self).__getitem__(index)

如果不扩展列表,可以使用相同的代码,但只返回无效索引的默认值

这保留了整个列表界面。

答案 4 :(得分:0)

(这不是一个新的答案;只是对unutbu的评论。应该可以在评论中发布这样的内容;它不是,所以我必须将其作为答案发布。)

CombineListClassesCombineListClasses2继承自两个都继承自list的类。行为和doctests很简单,但在原始版本中严重破坏。

这是Python数据模型中的所有标准做法;你几乎不应该直接调用基类方法,而不是通过super

class DefaultList(list):
    """
    >>> x = DefaultList('abc', default='*')
    >>> x
    ['a', 'b', 'c']
    >>> x[6] = 'g'
    >>> x
    ['a', 'b', 'c', '*', '*', '*', 'g']
    >>> x[2], x[4], x[6], x[8]  # should print 'c * g *'
    ('c', '*', 'g', '*')
    >>> x[2:9:2]
    ['c', '*', 'g', '*']

    >>> x = DefaultList()
    >>> x[1] = 'a'
    >>> x
    [None, 'a']

    >>> x = DefaultList(sequence=[1,2,3], default=5)
    >>> x
    [1, 2, 3]
    >>> x[10]
    5
    """
    def __init__(self, *args, **kwargs):
        if 'default' in kwargs:
            self.default = kwargs['default']
            del kwargs['default']
        else:
            self.default = None
        super(DefaultList, self).__init__(*args, **kwargs)

    def __getitem__(self, key):
        # retrieving an item does not expand the list
        if isinstance(key, slice):
            return [self[elt] for elt in range(key.start, key.stop, key.step)]
        else:
            try:
                return super(DefaultList, self).__getitem__(key)
            except IndexError:
                return self.default

    def __setitem__(self, key, value):
        # setting an item may expand the list
        try:
            super(DefaultList, self).__setitem__(key, value)
        except IndexError:
            self.extend([self.default]*(key-len(self)))
            self.append(value)

# Another class that derives from list:
class AddMethodToList(list):
    def __init__(self, *args, **kwargs):
        self.value = kwargs['value']
        del kwargs['value']
        super(AddMethodToList, self).__init__(*args, **kwargs)

    def new_method(self):
        return self.value

# Derive from both classes.
class CombineListClasses(AddMethodToList, DefaultList):
    """
    >>> a = CombineListClasses(default=10, sequence=[1,2,3], value=3)
    >>> a.new_method()
    3
    >>> a[5] = 1
    >>> a
    [1, 2, 3, 10, 10, 1]
    """
    pass

# Derive from both classes in reverse, reversing the call chain order.
class CombineListClasses2(DefaultList, AddMethodToList):
    """
    >>> a = CombineListClasses2(default=10, sequence=[1,2,3], value=3)
    >>> a.new_method()
    3
    >>> a[5] = 1
    >>> a
    [1, 2, 3, 10, 10, 1]
    """
    pass

if __name__ == '__main__':
    import doctest
    print doctest.testmod()

请注意,在Python 3中,语言直接支持:

class DefaultList(list):
    def __init__(self, *args, default=None, **kwargs):
        self.default = default
        super(self).__init__(*args, **kwargs)

但是在Python 2中不支持。http://www.python.org/dev/peps/pep-3102