Есть ли такой метод, как деление на или умножение на в Python Range ()? - PullRequest
3 голосов
/ 04 июня 2019

для Java, мы можем сделать:

for(int i=100; i>2 ; i=i/2){things to execute}

а что если в python?

есть что-нибудь вроде

for i in range(100:2:something)

может решить эту проблему?

Ответы [ 5 ]

9 голосов
/ 04 июня 2019

Если вам нужно что-то простое, что вы можете иметь под рукой в ​​нескольких местах, вы можете создать функцию генератора:

def range_divide(start, end, denominator): # TODO: Think for a better name!
    value = start
    while value > end:
        yield value
        value /= denominator

и затем

for value in range_divide(100, 2, 2):
    # do_stuff

Вы могли бы даже сделать это с помощью

def range_flexible(start, end, action):
    value = start
    while value > end:
        yield value
        value = action(value)

и до

for value in range_flexible(100, 2, lambda x: x/2):
    # do_stuff

или даже

def for_loop(start, cont_condition, action):
    value = start
    while cont_condition(value):
        yield value
        value = action(value)

for value in for_loop(100, lambda x: x > 2, lambda x: x/2):
    # do_stuff
5 голосов
/ 04 июня 2019

Нет использования диапазона, вы можете предварительно заполнить список и выполнить итерацию по нему, но вам лучше использовать цикл while.

i = 100
while i > 2:
     ...
     i = i / 2
2 голосов
/ 04 июня 2019

Если вы хотите, чтобы он больше походил на цикл java (или C) for, вы можете определить функцию, которая будет обрабатывать параметры в виде строки в стиле C (за счет скорости выполнения):

cachedCFor = dict()
def cFor(params):
    if params in cachedCFor: return cachedCFor[params]()
    setup,condition,step = [ p.strip() for p in params.split(";") ]
    varName   = setup.split("=",1)[0].strip()
    fn    = dict()
    code  = f"""
def iterator():
    {setup}
    while {condition}:
        yield {varName}
        {step}
"""
    exec(code,{},fn)
    cachedCFor[params] = fn["iterator"]
    return fn["iterator"]()

for i in cFor("i=100;i>2;i=i/2"):
    print(i)

100
50.0
25.0
12.5
6.25
3.125

Обратите внимание, что переменная i в строковом параметре является внутренней для итератора и недоступна в коде цикла for. Мы могли бы написать for i in cFor("x=100;x>2;x=x/2") и по-прежнему использовать i в цикле

При этом я бы по-прежнему предлагал вам принять способ работы Python и не пытаться воспроизводить синтаксис другого языка (т. Е. Использовать оператор while в данном конкретном случае)

например:

x = 100
while x > 2:
    i,x = x,x/2 # using x for the next value allows this to be placed
                # at the beginning of the loop (rather than at the end)
                # and avoids issues with the continue statement
    print(i)
    # ... your code ...

Или, вы можете использовать немного математики:

# 6 = int(math.log(100,2)) 
for i in [100/2**i for i in range(6)]:
    print(i) 

# Strangely enough, this is actually slower than the cFor() folly
1 голос
/ 07 июня 2019

Вот еще один подход для обработки специальных прогрессий более чистым и более общим способом. Это класс, который реализует (и скрывает) внутреннюю работу переменной цикла.

class Loop:
    def __init__(self,start=0):
        self._firstPass  = True
        self._value      = start

    @property
    def value(self): return self._value

    def start(self,initial):
        if self._firstPass : self._value = initial
        return self

    def next(self,nextValue=None):
        if nextValue is None : nextValue = self.value + self._increment
        if self._firstPass : self._firstPass = False
        else               : self._value = nextValue 
        return self

    def up(self,by=1):
        return self.next(self.value+by)
    def down(self,by=1):
        return self.next(self.value-by)

    def upTo(self,last,by=1):
        if self._firstPass: self._firstPass = False
        else: self._value  += by
        return self.value <= last

    def downTo(self,last,by=1):
        if self._firstPass: self._firstPass = False
        else: self._value  -= by
        return self.value >= last

    def loop(self,condition=True):
        self._firstPass = False
        return condition

    def until(self,condition=False):
        self._firstPass = False
        return not condition

    def __getitem__(self,index):     return self.value[index]
    def __str__(self):               return str(self.value)
    def __int__(self):               return int(self.value)
    def __float__(self):             return float(self.value)    
    def __add__(self,other):         return self.value + other
    def __sub__(self,other):         return self.value - other
    def __mul__(self,other):         return self.value * other
    def __matmul__(self,other):      return self.value.__matmul__(other)
    def __divmod__(self,other):      return divmod(self.value,other)
    def __pow__(self,other):         return self.value ** other
    def __truediv__(self,other):     return self.value / other
    def __floordiv__(self,other):    return self.value // other
    def __mod__(self,other):         return self.value % other
    def __lshift__(self,other):      return self.value << other
    def __rshift__(self,other):      return self.value >> other
    def __lt__(self,other):          return self.value < other
    def __le__(self,other):          return self.value <= other
    def __eq__(self,other):          return self.value == other
    def __ne__(self,other):          return self.value != other
    def __gt__(self,other):          return self.value > other
    def __ge__(self,other):          return self.value >= other
    def __and__(self,other):         return self.value & other
    def __or__(self,other):          return self.value | other
    def __xor__(self,other):         return self.value ^ other
    def __invert__(self):            return -self.value
    def __neg__(self):               return -self.value
    def __pos__(self):               return self.value
    def __abs__(self):               return abs(self.value)    
    def __radd__(self, other):       return other + self.value 
    def __rsub__(self, other):       return other - self.value
    def __rmul__(self, other):       return other * self.value
    def __rmatmul__(self, other):    return other.__matmul__(self.value)
    def __rtruediv__(self, other):   return other / self.value
    def __rfloordiv__(self, other):  return other // self.value
    def __rmod__(self, other):       return other % self.value
    def __rdivmod__(self, other):    return divmod(other,self.value)
    def __rpow__(self, other):       return other ** self.value
    def __rlshift__(self, other):    return other << self.value
    def __rrshift__(self, other):    return other >> self.value
    def __rand__(self, other):       return other & self.value
    def __rxor__(self, other):       return other ^ self.value
    def __ror__(self, other):        return other | self.value

Класс предназначен для работы с оператором while после инициализации переменной цикла. Переменная цикла ведет себя как обычный тип int (или float, или str и т. Д.), Когда используется в вычислениях и условиях. Это позволяет выражать условия прогрессии и остановки так, как вы бы записали их для обычной переменной цикла. Класс добавляет несколько методов для управления циклическим процессом с учетом нестандартных приращений / уменьшений:

Например:

i = Loop()
while i.start(100).next(i//2).loop(i>2):
    print(i) # 100, 50, 25, 12, 6 ,3

    # Note: to use i for assignment or as parameter use +i or i.value
    #       example1: j = +i   
    #       example2: for j in range(+i)
    #
    # i.value cannot be modified during the loop

Вы также можете указать начальное значение в конструкторе, чтобы сделать оператор while более кратким. Класс также имеет функцию till () для инвертирования условия остановки:

i = Loop(start=100)
while i.next(i//2).until(i<=2):
   print(i) # 100, 50.0, 25.0, 12.5, 6.25, 3.125

Наконец, есть пара вспомогательных функций для реализации более простых циклов (хотя for in, вероятно, будет лучше в большинстве случаев):

i = Loop()
while i.start(1).upTo(10):
    print(i) # 1,2,...,9,10

i = Loop()
while i.upTo(100,by=5):
    print(i) # 0,5,10,15,20,...,95,100

i = Loop(100)
while i.down(by=5).until(i<20):
    print(i) # 100,95,90,...,25,20
0 голосов
/ 07 июня 2019

Я не рекомендую использовать его на самом деле, поскольку @ glglgl's range_divide() продолжает вдвое быстрее работать с каждым тестируемым входом, но поклонникам itertools все еще может понравиться подумать об этом:

from itertools import takewhile, accumulate, chain, repeat
from operator import truediv, floordiv


def div_range(start, end, divisor, operator):
    return takewhile(
        lambda x: x > end, accumulate(chain([start], repeat(divisor)), operator)
    )


for i in div_range(100, 2, 2, truediv):
    print(i)

# Out:
100
50.0
25.0
12.5
6.25
3.125

for i in div_range(100, 2, 2, floordiv):
    print(i)

# Out:
100
50
25
12
6
3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...