Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python3.x移动范围_Python_Loops_Python 3.x_Range - Fatal编程技术网

Python3.x移动范围

Python3.x移动范围,python,loops,python-3.x,range,Python,Loops,Python 3.x,Range,假设我有这样一个范围: x = range(10) 将具有以下值作为列表: list(x) # Prints [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 我想改变这个范围(可能多次) 并对结果进行迭代,例如 # [7, 8, 9, 0, 1, 2, 3, 4, 5, 6] 创建等效列表不是问题。但是我想 知道是否有可能创造出这样的东西 一个范围可以在内存中节省一些空间,当然它会 如果解决方案的性能可以达到: for i i

假设我有这样一个范围:

x = range(10)
将具有以下值作为列表:

list(x)      # Prints [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
我想改变这个范围(可能多次) 并对结果进行迭代,例如

             #        [7, 8, 9, 0, 1, 2, 3, 4, 5, 6]
创建等效列表不是问题。但是我想 知道是否有可能创造出这样的东西 一个范围可以在内存中节省一些空间,当然它会 如果解决方案的性能可以达到:

for i in range(1000000)

可以在生成器表达式中包装范围,动态应用移位和模:

def shifted_range(rangeob, shift):
    size, shift = rangeob.stop, shift * rangeob.step
    return ((i + shift) % size for i in rangeob)
演示:

您还可以将其作为包装器对象:

class RangeShift:
    def __init__(self, rangeob, shift):
        self._range = rangeob
        self.shift = shift

    @property
    def start(self):
        r = self._range
        return (r.start + self.shift * r.step) % r.stop

    @property
    def stop(self):
        r = self._range
        return (r.stop + self.shift * r.step) % r.stop

    def index(self, value):
        idx = self._range.index(value)
        return (idx - self.shift) % len(self._range)

    def __getattr__(self, attr):
        return getattr(self._range, attr)

    def __getitem__(self, index):
        r = self._range
        return (r[index] + self.shift * r.step) % r.stop

    def __len__(self):
        return len(self._range)

    def __iter__(self):
        size, shift = self._range.stop, self.shift * self._range.step
        return ((i + shift) % size for i in self._range)
这将与原始范围一样,但会对生成的所有值应用移位。它甚至可以让你改变班次

演示:

此包装器现在支持的最佳技巧:反转移位范围:

>>> list(reversed(shifted))
[2, 1, 0, 9, 8, 7, 6, 5, 4, 3]
>>> list(reversed(shifted_10_2))
[6, 4, 2, 0, 8]

我想最简单的方法是将其分为两个范围:

from itertools import chain

shifted = chain(range(7, 10), range(7))
for x in shifted:
    print(x)

您可以使用itertools链接两个范围。即使范围的步长大于1,此代码也有效

import itertools

def shift_range(r, s):
    return itertools.chain(range(r.start + s*r.step, r.stop, r.step), 
                           range(r.start, r.start + s*r.step, r.step))
测试:

>>> list(shift_range(range(10), 5))
[5, 6, 7, 8, 9, 0, 1, 2, 3, 4]
>>> list(shift_range(range(3, 30, 3), 5))
[18, 21, 24, 27, 3, 6, 9, 12, 15]

谢谢你的详细回答。(我猜至少有一条包含感谢的评论是被允许的,不会被视为垃圾邮件):P
import itertools

def shift_range(r, s):
    return itertools.chain(range(r.start + s*r.step, r.stop, r.step), 
                           range(r.start, r.start + s*r.step, r.step))
>>> list(shift_range(range(10), 5))
[5, 6, 7, 8, 9, 0, 1, 2, 3, 4]
>>> list(shift_range(range(3, 30, 3), 5))
[18, 21, 24, 27, 3, 6, 9, 12, 15]