如何列出[n]指向列表[0]?不按顺序获取物品

时间:2014-08-20 14:30:38

标签: python

我不确定这项技术的用语。我想创建一个列表,如果我尝试访问列表范围之外的元素,列表将自行循环"。我想要实现的行为示例:

>>> musical_scale = ['C', 'D', 'E', 'F', 'G', 'A', 'B']
>>> musical_scale[2]
E
>>> musical_scale[7]
C
>>> musical_scale[-1]
B

我想我可以编写一个这样做的类,但我认为可能有更正确的方法。

4 个答案:

答案 0 :(得分:4)

创建List的子类将是一种非常有用的方法。这样的事情,也许是:

class modList(list):

  def __getitem__(self, i):
    if len(self) == 0:
      raise IndexError   # Or do something else if you want, like return []
    i = i % len(self)   # self.__len__() works also
    return super(modList, self).__getitem__(i)   # In Python 3, super().__getitem__(i)

如果你想做切片,它有点复杂,但相似。通过StackOverflow查找此内容:

  def __getitem__(self, i):
    if isinstance(i, int):
      if len(self) == 0:
        raise IndexError
      i = i % len(self)
      return super(modList, self).__getitem__(i)   # list.__getitem__(i) works too
    elif isinstance(i, slice):
      if len(self) == 0:
        return []
      start = i.start % len(self)
      stop = i.stop % len(self)
      step = i.step
      return super(modList, self).__getItem__(slice(start, stop, step))
    else:
      raise TypeError("invalid index")

虽然这个切片修改可能会给你一个类似[3:2]的情况,它将返回一个空列表。基本上切片很难,你需要决定如何实现它,但希望这是一个开始。

http://www.stackoverflow.com/questions/3911483/python-slice-how-to-i-know-the-python-slice-but-how-can-i-use-built-in-slice-ob

(感谢@JonClements提供聊天中的所有建议。)

编辑:现在我们有一些处理程序,如果你有一个空列表。 @wim建议为单次访问引发错误,并为切片返回[]。真的,这取决于你想要做什么,但这对我来说似乎是明智的,所以这就是我在这个答案中所包含的内容。

编辑编辑:如果您使用的是Python 2.x,我相信您还需要覆盖__getslice__

答案 1 :(得分:3)

使用模数运算符%来"循环返回"索引超过列表末尾

>>> musical_scale = ['C', 'D', 'E', 'F', 'G', 'A', 'B']

def getValue(x, l):
    return l[x % len(l)]

>>> getValue(0, musical_scale)
'C'
>>> getValue(9, musical_scale)
'E'

答案 2 :(得分:0)

如果您想扩展列表类以处理获取和设置...

class UnsatList(list):
    def __getitem__(self, index):
        try:
            return list.__getitem__(self, index % len(self))
        except ZeroDivisionError:
            raise IndexError('list assignment index out of range')

    def __setitem__(self, index, value):
        try:
            return list.__setitem__(self, index % len(self), value)
        except ZeroDivisionError:
            raise IndexError('list assignment index out of range')


if __name__ == '__main__':
    test_list = UnsatList([1,2,3,4])
    assert test_list[0] == 1
    assert test_list[4] == 1
    assert test_list[8] == 1
    assert test_list[-8] == 1
    test_list[4] = 5
    assert test_list[0] == 5
    assert test_list[4] == 5
    assert test_list[8] == 5
    assert test_list[-8] == 5

答案 3 :(得分:0)

这是一个解决方案,但请记住The Zen of Python Flat优于嵌套。

您可以编写例如:

a = [1, [2]]
a[1].append(a)

然后你的列表a具有“无限深度”,你可以通过反复执行以下来循环这两个元素:

a[0]
a = a[1]

如果不玩深度,你不能这样做,因为不像Lisp,Python列表是变长数组,而不是链表。

以下是自动执行整个操作的小功能:

def loopify(a):
    r = b = []
    for x in a:
        b.append(x)
        b.append([])
        c = b
        b = b[1]
    c[1] = r
    return r

def loopgen(a):
    while True:
        yield a[0]
        a = a[1]

然后用你的例子:

musical_scale = loopify(['C', 'D', 'E', 'F', 'G', 'A', 'B'])
g = loopgen(musical_scale)
[next(g) for i in range(20)]

这会产生:

['C','D','E','F','G','A','B','C','D','E','F','G ','A','B','C','D','E','F','G','A']

当然,也可以使用mod或跟踪当前索引,并在溢出列表时将其重置为0。其他答案告诉你如何做到这一点。

另请注意,链表方法不允许随机访问,只允许顺序访问(因此上面的生成器)。如果您需要随机访问列表,模块化算法是最合适的方法。