假设我有一个数组foo
,例如元素[1, 2, 3]
,我希望检索foo
的元素,就好像foo
已经“无限连接”。
例如foo[0:2]
会返回(就像普通列表一样):
[1, 2]
和foo[0:5]
会返回:
[1, 2, 3, 1, 2]
而foo[7:13]
会返回:
[2, 3, 1, 2, 3, 1]
Python或扩展模块中是否有任何数据容器已经促进了此类访问?如果没有,那么提供这个容器的好方法是什么?
答案 0 :(得分:11)
我担心你必须自己实施它。但这并不困难:
class cyclist(list):
def __getitem__(self, index):
return list.__getitem__(self, index % len(self))
def __getslice__(self, start, stop):
return [self[n] for n in range(start, stop)]
foo = cyclist([1, 2, 3])
print foo[0:2] # [1, 2]
print foo[7:13] # [2, 3, 1, 2, 3, 1]
print foo[0:5] # [1, 2, 3, 1, 2]
缺少一些细节,例如处理省略的切片参数,切片中的负数和切片步骤。
答案 1 :(得分:2)
使用看起来像列表但行为本身不同的序列时应该小心。
我建议使用Pavel Anossov的酷实现,但提供指定的get_cyclic_item
和
get_cyclic_slice
,而不是覆盖列表的__getitem__
和__getslice__
。
该类的用户可以轻松地假设他正在使用的列表的行为(期望ISA关系,如“循环列表是一个列表”),这将导致错误/错误。
以下是一些例子,如果调用者不知道他使用的是cyclicallist
而不是常规列表,那么使用您的列表会让人感到困惑......
a = cyclicallist([ 0, 1, 2 ])
# appending a value at the end changes an "existing" index
print a[100]
a.append(99)
print a[100]
# deleting a value changes an index preceding it
print a[100]
del a[999] # currently gives an error: IndexError: list assignment index out of range
print a[100] # even if no error, what should this print?
# hmm...
del a[100:99999]
当然,空cyclicallist
的语义没有明确定义......
答案 2 :(得分:2)
与上面建议的基于模数的实现相比,即使它的效率低得离谱,我认为使用itertools
可能是一种有趣的方式...
>>> from itertools import islice, cycle
>>> make_cyclic = lambda lst: lambda start, stop: list( islice( cycle( lst ), start, stop ) )
>>> make_cyclic( [ 1, 2, 3 ] )
>>> c(7, 13)
[2, 3, 1, 2, 3, 1]