【问题标题】:Cyclical indexing of lists in PythonPython中列表的循环索引
【发布时间】:2013-03-15 20:26:15
【问题描述】:

假设我有一个数组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 中是否有任何数据容器或扩展模块已经促进了这种类型的访问?如果没有,提供这个容器的好/简单的方法是什么?

【问题讨论】:

    标签: python data-structures


    【解决方案1】:

    恐怕你必须自己实现它。不过这并不难:

    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]
    

    它缺少一些细节,例如处理省略的切片参数、切片中的负数和切片步骤。

    【讨论】:

      【解决方案2】:

      在处理看起来像列表但行为本质上不同的序列时,您应该小心。 我建议使用 Pavel Anossov 的酷实现,但提供指定的 get_cyclic_itemget_cyclic_slice,而不是覆盖列表的 __getitem____getslice__

      该类的用户可以轻松地对他正在使用的列表的行为做出假设(期望 ISA 关系,如“cyclicallist IS A list”),这会导致错误/错误。

      如果调用者不知道他使用的是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 的语义没有明确定义...

      【讨论】:

      • 我不知道 OP 的上下文,但大多数问题似乎可以通过将新数据结构定义为不可变类型来解决,这对他/她来说已经足够了。不是你错了——我也会用你的方法! - 但有趣的是,这样的约束可以解决一些问题,如果 OP 确实需要这种行为,那么该约束可能在 OP 的问题中也是有效的。
      • @brandizzi,说得好。也许class cyclicaltuple(tuple): ... 是要走的路。
      • 元组在语义上是错误的。元组是具有固定且已知数量的元素的记录。你也不能称它为cyclist :) 我认为发音为cyclists immutable 就足够了(可能继承自collections.Sequence)。
      • 我听说您无法将其称为 cyclist。一个明显的交易破坏者。但我不确定我理解你对语义的意思。我仅将元组视为不可变列表。
      【解决方案3】:

      即使与上面建议的基于模的实现相比效率低得离谱,我认为使用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]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-07
        • 2015-11-10
        • 2016-10-03
        • 2019-05-09
        • 1970-01-01
        • 1970-01-01
        • 2019-01-07
        • 1970-01-01
        相关资源
        最近更新 更多