2016-06-15 5 views
19

Я пытаюсь установить петлю между 0,01 и 10, но между 0,01 и 0,1 используют 0,01 в качестве шага, затем между 0,1 и 1,0 используют 0,1 в качестве шага и от 1,0 до 10,0 используют 1,0 в качестве шага.Переменная шаг в цикле for

У меня есть код цикла while написанный, но вы хотите сделать его более питоновским.

i = 0.01 
while i < 10: 
    # do something 
    print i 
    if i < 0.1: 
     i += 0.01 
    elif i < 1.0: 
     i += 0.1 
    else: 
     i += 1 

Это произведет

0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 2, 3, 4, 5, 6, 7, 8, 9 
+3

положить, что в функции и добавить 'выход i' в качестве последней команды цикла. Это будет генератор, который вы можете повторить. – njzk2

+6

Остерегайтесь - приращение по шагам не очень хорошо работает с ограничениями округления с плавающей запятой. Вероятно, у вас будут пограничные ошибки. – user2357112

+1

@ njzk2 - 'yield' должен быть ** первым ** инструкцией в его цикле, где' # do something' теперь. Его первое значение должно быть '.01'. –

ответ

3

Вы могли бы иметь вложенный цикл, внешний тот, который перебирает точности и внутренней один, который просто range(1,10):

for precision in (0.01, 0.1, 1): 
    for i in range(1,10): 
     i*=precision 
     print(i) 

Однако поплавки вероятно, не будет работать в этом случае, так как это показывает значения, такие как 0.30000000000000004 на моей машине, для точных десятичных значений вы хотели бы использовать decimal м МОДУЛЬ:

import decimal 
for precision in ("0.01", "0.1", "1"): 
    for i in range(1,10): 
     i*=decimal.Decimal(precision) 
     print(i) 
+0

Да, исправлено это тоже сейчас, я не знаю, в моей голове сейчас нет. –

3

Один подход заключается в использовании двух петель: один для порядка, и один для значений от 1 до 9:

функционального генератора
for exp in range(-2, 1): 
    for i in range(1, 10): 
     print("{:.2f}".format(i * 10 ** exp)) 
20

специального кошелек может быть правильный путь. Это эффективно отделяет скучную часть (получая список цифр справа) от интересной части (# do something в вашем примере).

def my_range(): 
    for j in .01, .1, 1.: 
     for i in range(1, 10, 1): 
      yield i * j 

for x in my_range(): 
    print x 
+0

Это в основном работает. Вы получаете нечетные результаты, такие как '' 0.30000000000000004''. –

+1

Конечно. Такова природа арифметики с плавающей запятой. '0.3' не может быть представлен в' float'. –

+1

Yup, не удивительно с моей стороны. Я сделал этот комментарий для ОП. –

1

Вы могли бы сделать что-то вроде:

import numpy as np 
list1 = np.arange(0.01, 0.1, 0.01) 
list2 = np.arange(0.1, 1, 0.1) 
list3 = np.arange(1, 10, 1) 
i_list = np.concatenate((list1, list2, list3)) # note the double parenthesis 
for i in i_list: 
    ... 

В основном вы создаете весь список значений, которые вам нужны фронт, i_list, то просто перебирать их в вашем for цикле.

3

Только одна строка кода через список понимания -

for k in [i*j for j in (0.01, 0.1, 1) for i in range(1, 10)] 

не может быть более вещий!

+3

Вам не требуется назначение. OP хочет использовать это для управления циклом: 'for x in (i * j для j in (.01, .1, 1.) для i в диапазоне (1,10)): print x' –

+1

Да, просто, просто починил это. – hashcode55

+0

:(Кажется довольно ухищренным, чтобы иметь 3 'for' оператора в одной строке. Я предпочел это другим способом. –

1

Только в случае, если вы хотели бы заменить петлю векторизованного код ...

In [63]: np.ravel(10.**np.arange(-2, 1)[:,None] * np.arange(1, 10)[None,:]) 
Out[64]: 
array([ 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 
     0.1 , 0.2 , 0.3 , 0.4 , 0.5 , 0.6 , 0.7 , 0.8 , 0.9 , 
     1. , 2. , 3. , 4. , 5. , 6. , 7. , 8. , 9. ]) 
+2

Numpy - это избыточный путь для этой проблемы – Mego

+0

Да, мой код можно рассматривать как своего рода излишний, если вам просто нужно чтобы напечатать номера (BTW, мое не единственное решение на основе NumPy, предлагаемое здесь). Однако, если блок '' # сделать что-то '' включает вызов временной функции, которая принимает сгенерированные значения как аргумент, я думаю, что векторизованный код может быть более эффективным.В любом случае это просто еще один возможный подход, который некоторые пользователи SO могли бы найти полезными. – Tonechas

2

Я бы рекомендовал функцию генератора, а также, но если шаги не такие удобные полномочия друг друга Я пишу это как

def my_range(): 
    i = 0 
    while i < 0.1: 
     i += 0.01 
     yield i 
    while i < 1: 
     i += 0.1 
     yield i 
    while i < 10: 
     i += 1 
     yield i 

for x in my_range(): 
    print x 

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

Если она становится слишком повторяющейся, используйте

def my_range(): 
    i = 0 
    for (end, step) in [(0.1, 0.01), (1, 0.1), (10, 1)]: 
     while i < end: 
      i += step 
      yield i 
+0

Как и любое другое назначение, '+ =' присваивания - это инструкции в Python, вы не можете ' yield' them. – user2357112

+0

@ user2357112: правый, фиксированный. – Bergi